Deserialize JSON collection to collection of Objects using Jackson
suggest changeSuppose 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:
TypeReference
should be instantiated using anonymous class- You should provide generic explicity
Failing to do so may lead to loss of generic type argument which will lead to deserialization failure.