Course – LS – NPI (cat=JSON/Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING

1. Background

Jackson is a popular Java library to serialize Java objects to JSON and vice versa. In some cases, the Java objects could be defined with a generic type.

In this tutorial, we’ll illustrate how to use Jackson to deserialize a JSON string into a generic type.

2. Models Preparation

For the given JSON string to be deserialized:

{"result":{"id":1,"firstName":"John","lastName":"Lewis"}}

we need to define a class with a generic type parameter and a regular POJO object to hold the data:

public class JsonResponse<T> {
    private T result;

    // getters and setters...
}
public class User {
    private Long id;
    private String firstName;
    private String lastName;

    // getters and setters...
}

3. Deserialize Generic Type

In Jackson, ObjectMapper provides three sets of readValue methods for JSON deserialization that take:

  • Class<T> as a parameter to pass the type of information
  • TypeReference to pass the type information
  • JavaType as the parameter

We can’t use JsonResponse<User>.class to pass to methods from the first bullet point, so let’s see how to do generics deserialization using TypeReference and JavaType.

3.1. TypeReference

As well known, Java erases generic type information during compilation, but we can take advantage of the power of anonymous inner classes to preserve the type information during compile time. Jackson provides the abstract class TypeReference to obtain the type information from the derivated subclasses:

public abstract class TypeReference<T> { 
    protected final Type _type;

    protected TypeReference() {
        Type superClass = this.getClass().getGenericSuperclass();
        this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0]; 
    } 
}

With TypeReference, we can create an anonymous inner class for the generic type JsonResponse<User> as follows:

TypeReference<JsonResponse<User>> typeRef = new TypeReference<JsonResponse<User>>() {};

This approach for preserving the generic type information is known as a super type token. By using super type tokens, Jackson will know that the container type is JsonResponse and its type parameter is User. 

Here is the complete test case for the deserialization:

@Test
void givenJsonObject_whenDeserializeIntoGenericTypeByTypeReference_thenCorrect() throws JsonProcessingException {
    String json = "{\"result\":{\"id\":1,\"firstName\":\"John\",\"lastName\":\"Lewis\"}}";

    TypeReference<JsonResponse<User>> typeRef = new TypeReference<JsonResponse<User>>() {};
    JsonResponse<User> jsonResponse = objectMapper.readValue(json, typeRef);
    User user = jsonResponse.getResult();

    assertThat(user.getId()).isEqualTo(1);
    assertThat(user.getFirstName()).isEqualTo("John");
    assertThat(user.getLastName()).isEqualTo("Lewis");
}

3.2. JavaType

If the type parameter T is not static, we need to choose JavaType instead of TypeReference to pass the type information for deserialization. ObjectMapper provides such methods, which are recommended now from Jackson 2.5, and we can use TypeFactory to construct the JavaType object with our type parameter:

JavaType javaType = objectMapper.getTypeFactory().constructParametricType(JsonResponse.class, User.class);
JsonResponse<User> jsonResponse = objectMapper.readValue(json, javaType);

Here User.class is passed as the second parameter to the method constructParametricType, and it can be easily changed to other parameterized types.

4. Conclusion

In this article, we have introduced two simple ways to deserialize a JSON string into an object with a generic type.

As usual, all code snippets presented in this article are available on over on GitHub.

Course – LS (cat=JSON/Jackson)
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

res – Jackson (eBook) (cat=Jackson)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.