Background:
I am getting mismatchedInputException, when parsing json.
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type java.util.ArrayList<Data>
from Object value (token JsonToken.START_OBJECT
)
Problem:
nodes is a json-array which contains data, which can be either json-object or json-array .
I need to represent this correctly in POJO.
Things Tried: Map<String, Object>, List, ,@JsonDeserialize(using = NodeDeserializer.class)
Below is my nested json document for ref.
{
"parent": {
"nodes": [
{
"data": {
"desc": "a1",
"url": "http://a1.a11"
}
},
{
"data": [
{
"desc": "b1",
"url": "http://b1.b11"
},
{
"desc": "b2",
"url": "http://b2.b21"
}
]
}
]
}
}
Below is Pojo Java classes and Runner class, I am using for SER/DE for above Json
Data.java
import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
class Data {
@JsonProperty("desc")
private String desc;
@JsonProperty("url")
private String url;
}
Node.java
import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
class Node {
@JsonProperty("data")
//Map<String, Object> data = new LinkedHashMap<>();
//private List<Object> data;
private List<Data> data;
}
Parent.java
import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
class Parent {
@JsonProperty("nodes")
private List<Node> nodes;
}
Test.java
import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Test {
@JsonProperty("parent")
private Parent parent;
}
Runner Class
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
public class TestJsonParse {
public static void main(String[] args) throws JsonProcessingException {
String jsonString = "{\n" +
" \"parent\": {\n" +
" \"nodes\": [\n" +
" {\n" +
" \"data\": {\n" +
" \"desc\": \"a1\",\n" +
" \"url\": \"http://a1.a11\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"data\": [\n" +
" {\n" +
" \"desc\": \"b1\",\n" +
" \"url\": \"http://b1.b11\"\n" +
" },\n" +
" {\n" +
" \"desc\": \"b2\",\n" +
" \"url\": \"http://b2.b21\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
" }\n" +
"}";
// print pojo
ObjectMapper objectMapper = new ObjectMapper();
Test test = objectMapper.readValue(jsonString, Test.class);
System.out.println(test);
}
}
How to write common pojo deserializer for json attribute which can be an object and an array both?
It is possible if you use the JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY
deserialization feature consisting of an override for the DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY
feature which allows deserialization of JSON non-array values into single-element Java arrays and Collections. So you can annotate the data
field of your Node
class to obtain the expected behaviour:
class Node {
@JsonProperty("data")
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Data> data;
}