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.
String jsonString = "[{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]"
CollectionType listType =
factory.constructCollectionType(List.class, Person.class);
List<Preson> list = mapper.readValue(jsonString, listType);
TypeReference<Person> listType = new TypeReference<List<Person>>() {};
List<Person> list = mapper.readValue(jsonString, listType);
String jsonString = "{\"0\": {\"name\": \"Alice\"}, \"1\": {\"name\": \"Bob\"}}"
CollectionType mapType =
factory.constructMapLikeType(Map.class, String.class, Person.class);
List<Person> list = mapper.readValue(jsonString, mapType);
TypeReference<Person> mapType = new TypeReference<Map<String, Person>>() {};
Map<String, Person> list = mapper.readValue(jsonString, mapType);
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();
While TypeReference
approach may look better it has several drawbacks:
TypeReference
should be instantiated using anonymous classFailing to do so may lead to loss of generic type argument which will lead to deserialization failure.