Java Jackson Deserialization of Nested Objects

Jackson - How to process (deserialize) nested JSON?

Your data is problematic in that you have inner wrapper objects in your array. Presumably your Vendor object is designed to handle id, name, company_id, but each of those multiple objects are also wrapped in an object with a single property vendor.

I'm assuming that you're using the Jackson Data Binding model.

If so then there are two things to consider:

The first is using a special Jackson config property. Jackson - since 1.9 I believe, this may not be available if you're using an old version of Jackson - provides UNWRAP_ROOT_VALUE. It's designed for cases where your results are wrapped in a top-level single-property object that you want to discard.

So, play around with:

objectMapper.configure(SerializationConfig.Feature.UNWRAP_ROOT_VALUE, true);

The second is using wrapper objects. Even after discarding the outer wrapper object you still have the problem of your Vendor objects being wrapped in a single-property object. Use a wrapper to get around this:

class VendorWrapper
{
Vendor vendor;

// gettors, settors for vendor if you need them
}

Similarly, instead of using UNWRAP_ROOT_VALUES, you could also define a wrapper class to handle the outer object. Assuming that you have correct Vendor, VendorWrapper object, you can define:

class VendorsWrapper
{
List<VendorWrapper> vendors = new ArrayList<VendorWrapper>();

// gettors, settors for vendors if you need them
}

// in your deserialization code:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readValue(jsonInput, VendorsWrapper.class);

The object tree for VendorsWrapper is analogous to your JSON:

VendorsWrapper:
vendors:
[
VendorWrapper
vendor: Vendor,
VendorWrapper:
vendor: Vendor,
...
]

Finally, you might use the Jackson Tree Model to parse this into JsonNodes, discarding the outer node, and for each JsonNode in the ArrayNode, calling:

mapper.readValue(node.get("vendor").getTextValue(), Vendor.class);

That might result in less code, but it seems no less clumsy than using two wrappers.

Simple Jackson deserialization of nested objects

You have to create the POJO and then use the Jackson ObjectMapper API to read the JSON string to java object.

Here is the working code basing on your sample string.

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "info", "data" })
public class Process {

@JsonProperty("info")
private String info;
@JsonProperty("data")
private Data data;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("info")
public String getInfo() {
return info;
}

@JsonProperty("info")
public void setInfo(String info) {
this.info = info;
}

@JsonProperty("data")
public Data getData() {
return data;
}

@JsonProperty("data")
public void setData(Data data) {
this.data = data;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "id", "cars" })
public class Data {

@JsonProperty("id")
private String id;
@JsonProperty("cars")
private List<Car> cars = null;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("id")
public String getId() {
return id;
}

@JsonProperty("id")
public void setId(String id) {
this.id = id;
}

@JsonProperty("cars")
public List<Car> getCars() {
return cars;
}

@JsonProperty("cars")
public void setCars(List<Car> cars) {
this.cars = cars;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}


@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "id" })
public class Car {

@JsonProperty("id")
private String id;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("id")
public String getId() {
return id;
}

@JsonProperty("id")
public void setId(String id) {
this.id = id;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

Code to deserialize the JSON string.

import java.io.IOException;
import java.util.List;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MainApp {

public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {

String input = "{\r\n" +
" \"info\": \"processing\",\r\n" +
" \"data\": {\r\n" +
" \"id\": \"123\",\r\n" +
" \"cars\": [\r\n" +
" {\r\n" +
" \"id\": \"1\"\r\n" +
" },\r\n" +
" {\r\n" +
" \"id\": \"2\"\r\n" +
" }\r\n" +
" ]\r\n" +
" }\r\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
Process process = mapper.readValue(input, Process.class);
System.out.println(process.getInfo());
Data data = process.getData();
List<Car> cars = data.getCars();
for(Car car : cars) {
System.out.println(car.getId());
}

}

}

Hope this helps.

How can I deserialize a nested wrapped String in Jackson?

When internal object is escaped JSON String we need to deserialise it "twice". First time is run when root JSON Object is deserialised and second time we need to run manually. To do that we need to implement custom deserialiser which implements com.fasterxml.jackson.databind.deser.ContextualDeserializer interface. It could look like this:

class FromStringJsonDeserializer<T> extends StdDeserializer<T> implements ContextualDeserializer {

/**
* Required by library to instantiate base instance
* */
public FromStringJsonDeserializer() {
super(Object.class);
}

public FromStringJsonDeserializer(JavaType type) {
super(type);
}

@Override
public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getValueAsString();

return ((ObjectMapper) p.getCodec()).readValue(value, _valueType);
}


@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
return new FromStringJsonDeserializer<>(property.getType());
}
}

We need to annotate our property with this class:

@JsonDeserialize(using = FromStringJsonDeserializer.class)
public final Address address;

Since now, you should be able to deserialise above JSON payload to your POJO model.

See also:

  • How to inject dependency into Jackson Custom deserializer
  • Is it possible to configure Jackson custom deserializers at class level for different data types?

Jackson deserialization of nested objects of which one references the other. UnresolvedForwardReference

Put your @JsonIdentityInfo annotation on the Node class, not the field in Force:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "number")
public static class Node { //...

Deserialize json with list of nested objects

You have two arrays in your JSON payloads. So, you need to create extra POJO for it. See below example:

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.util.List;

public class JsonApp {

public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();

ObjectMapper mapper = new ObjectMapper();
Root root = mapper.readValue(jsonFile, Root.class);
System.out.println(root);
}
}

class Root {

private Class1 class1;

//getters, setters, toString
}

class Class1 {

private String prop1;
private List<NestedProps> prop2;

//getters, setters, toString
}

class NestedProps {

private List<NestedProp> nestedProp;

//getters, setters, toString
}

class NestedProp {
private String p1;
private String p2;

//getters, setters, toString
}

For below JSON:

{
"class1": {
"prop1": "pp",
"prop2": [
{
"nestedProp": [
{
"p1": "127",
"p2": "1"
},
{
"p1": "128",
"p2": "2"
}
]
}
]
}
}

Above example prints:

Root{class1=Class1{prop1='pp', prop2=[NestedProps{nestedProp=[NestedProp{p1='127', p2='1'}, NestedProp{p1='128', p2='2'}]}]}}

See also:

  • Array of JSON Object to Java POJO


Related Topics



Leave a reply



Submit