Deserialize nested array as ArrayList with Jackson Deserialize nested array as ArrayList with Jackson arrays arrays

Deserialize nested array as ArrayList with Jackson


I see at least two approaches to do this if you want to get rid of wrapper classes. The first is to use the Jackson Tree Model (JsonNode) and the second is to use a deserialization feature called UNWRAP_ROOT_VALUE.


Alternative 1: Use JsonNode

When deserializing JSON using Jackson there are multiple ways to control what type of objects that are to be created. The ObjectMapper can deserialize the JSON to e.g. a Map, JsonNode (via the readTree-method) or a POJO.

If you combine the readTree-method with the POJO conversion the wrappers can be completely removed. Example:

// The author class (a bit cleaned up)public class Author {    private final String givenName;    private final String surname;    @JsonCreator    public Author(            @JsonProperty("given-name") final String givenName,            @JsonProperty("surname") final String surname) {        this.givenName = givenName;        this.surname = surname;    }    public String getGivenName() {        return givenName;    }    public String getSurname() {        return surname;    }}

The deserialization can then look something like this:

// The JSONfinal String json = "{\"authors\":{\"author\":[{\"given-name\":\"AdrienneH.\",\"surname\":\"Kovacs\"},{\"given-name\":\"Philip\",\"surname\":\"Moons\"}]}}";ObjectMapper mapper = new ObjectMapper();// Read the response as a tree modelfinal JsonNode response = mapper.readTree(json).path("authors").path("author");// Create the collection type (since it is a collection of Authors)final CollectionType collectionType =        TypeFactory                .defaultInstance()                .constructCollectionType(List.class, Author.class);// Convert the tree model to the collection (of Author-objects)List<Author> authors = mapper.reader(collectionType).readValue(response);// Now the authors-list is ready to use...

If you use this Tree Model-approach the wrapper classes can be completely removed.


Alternative 2: remove one of the wrappers and unwrap the root valueThe second approach is to remove only one of the wrappers. Assume that you remove the Authors class but keep the Response-wrapper. If you add the a @JsonRootName-annotation you can later unwrap the top-level name.

@JsonRootName("authors") // This is new compared to your examplepublic class Response {    private final List<Author> authors;    @JsonCreator    public Response(@JsonProperty("author") final List<Author> authors) {        this.authors = authors;    }    @JsonProperty("author")    public List<Author> getAuthors() {        return authors;    }}

Then, for your mapper simply use:

ObjectMapper mapper = new ObjectMapper();// Unwrap the root value i.e. the "authors"mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);final Response responsePojo = mapper.readValue(json, Response.class);

The second approach only removes one of the wrapper classes but instead the parsing function is quite pretty.