Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson - Deserialize using generic class

You need to create a TypeReference object for each generic type you use and use that for deserialization. For example -

mapper.readValue(jsonString, new TypeReference<Data<String>>() {});

You can't do that: you must specify fully resolved type, like Data<MyType>. T is just a variable, and as is meaningless.

But if you mean that T will be known, just not statically, you need to create equivalent of TypeReference dynamically. Other questions referenced may already mention this, but it should look something like:

public Data<T> read(InputStream json, Class<T> contentClass) {
   JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass);
   return mapper.readValue(json, type);
}

First thing you do is serialize, then you can do deserialize.
so when you do serialize, you should use @JsonTypeInfo to let jackson write class information into your json data. What you can do is like this:

Class Data <T> {
    int found;
    @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
    Class<T> hits
}

Then when you deserialize, you will find jackson has deserialize your data into a class which your variable hits actually is at runtime.


From Jackson 2.5, an elegant way to solve that is using the TypeFactory.constructParametricType(Class parametrized, Class... parameterClasses) method that allows to define straigthly a Jackson JavaType by specifying the parameterized class and its parameterized types.

Supposing you want to deserialize to Data<String>, you can do :

// the json variable may be a String, an InputStream and so for...
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class);
Data<String> data = mapper.readValue(json, type);

Note that if the class declared multiple parameterized types, it would not be really harder :

class Data <T, U> {
    int found;
    Class<T> hits;
    List<U> list;
}

We could do :

JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class, Integer);
Data<String, Integer> data = mapper.readValue(json, type);