Search code examples
javajsonjacksondeserializationresttemplate

Deserialize values in a tree structured JSON using Jackson


Need to deserialize a JSON structure like below using Jackson, this is a response from a REST API and I am using Spring RestTemplate with MappingJackson2HttpMessageConverter to parse it.

Problems: 1. All elements can have one or more child elements of its own type (e.g. root has children : childABC & childAnyRandomName) 2. Child nodes do not have a standard naming convention, names can be any random string.

{ "FooBar": { "root": { "name": "test1", "value": "900", "childABC": { "name": "test2", "value": "700", "childXYZ": { "name": "test3", "value": "600" } }, "childAnyRandomName": { "name": "test4", "value": "300" } } } }

As per my understanding, a POJO to store this could be something like this:

import java.util.Map;

public class TestObject {

private String name;
private String value;
private Map<String, TestObject> children;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}

public Map<String, TestObject> getChildren() {
    return children;
}

public void setChildren(Map<String, TestObject> children) {
    this.children = children;
}

}

I have no control over the actual JSON that I am parsing so If Jackson does not work, I will have to push all of it in JsonNode and build this object structure with custom logic.

Disclaimer: I am relatively new to Jackson, so please don't mind if this was a classic text book solution that I didn't read, just point me to the documentation location.


Solution

  • In your bean, have the attributes you know are there:

    private String blah;
    
    @JsonProperty("blah")
    @JsonSerialize(include = Inclusion.NON_NULL)
    public String getBlah() {
        return blah;
    }
    
    @JsonProperty("blah")
    public void setBlah(String blah) {
        this.blah = blah;
    }
    

    Then, add the following, which is kinda like a catch-all for any properties which you haven't explicitly mapped that appear on the JSON:

    private final Map<String, JsonNode> properties = new HashMap<String, JsonNode>();
    
    @JsonAnyGetter
    public Map<String, JsonNode> getProperties() {
        return properties;
    }
    
    @JsonAnySetter
    public void setProperty(String key, JsonNode value) {
        properties.put(key, value);
    }
    

    Alternatively, just map known complex objects to Map fields (IIRC, complex objects under that will also end up in maps).