Java Language JSON in Java Deserialize JSON collection to collection of Objects using Jackson


Example

Suppose you have a pojo class Person

public class Person {
    public String name;

    public Person(String name) {
        this.name = name;
    }
}

And you want to parse it into a JSON array or a map of Person objects. Due to type erasure you cannot construct classes of List<Person> and Map<String, Person> at runtime directly (and thus use them to deserialize JSON). To overcome this limitation jackson provides two approaches - TypeFactory and TypeReference.

TypeFactory

The approach taken here is to use a factory (and its static utility function) to build your type for you. The parameters it takes are the collection you want to use (list, set, etc.) and the class you want to store in that collection.

TypeReference

The type reference approach seems simpler because it saves you a bit of typing and looks cleaner. TypeReference accepts a type parameter, where you pass the desired type List<Person>. You simply instantiate this TypeReference object and use it as your type container.

Now let's look at how to actually deserialize your JSON into a Java object. If your JSON is formatted as an array, you can deserialize it as a List. If there is a more complex nested structure, you will want to deserialize to a Map. We will look at examples of both.

Deserializing JSON array

String jsonString = "[{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]"

TypeFactory approach

CollectionType listType = 
    factory.constructCollectionType(List.class, Person.class);
List<Preson> list = mapper.readValue(jsonString, listType);

TypeReference approach

TypeReference<Person> listType = new TypeReference<List<Person>>() {};
List<Person> list = mapper.readValue(jsonString, listType);

Deserializing JSON map

String jsonString = "{\"0\": {\"name\": \"Alice\"}, \"1\": {\"name\": \"Bob\"}}"

TypeFactory approach

CollectionType mapType = 
    factory.constructMapLikeType(Map.class, String.class, Person.class);
List<Person> list = mapper.readValue(jsonString, mapType);

TypeReference approach

TypeReference<Person> mapType = new TypeReference<Map<String, Person>>() {};
Map<String, Person> list = mapper.readValue(jsonString, mapType);

Details

Import statement used:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;

Instances used:

ObjectMapper mapper = new ObjectMapper();
TypeFactory factory = mapper.getTypeFactory();

Note

While TypeReference approach may look better it has several drawbacks:

  1. TypeReference should be instantiated using anonymous class
  2. You should provide generic explicity

Failing to do so may lead to loss of generic type argument which will lead to deserialization failure.