java jackson parse object containing a generic type object

generics, jackson, java, json, parsing

Solution

I agree with eugen's answer but just wanted to expand on it a bit. The first step is to refactor your parse method so it takes a second argument. Instead of allocating the type reference in your method, you require the caller to pass in a TypeReference instance.

public BaseResponseModel<T> parse(String responseBody, TypeReference<T> ref) throws Exception {
    return mapper.readValue(responseBody, ref);
}

Unfortunately your snippet does not show the code which calls parse - so I'll make something up:

BaseResponseParser<Collection<Person>> parser = new BaseResponseParser<Collection<Person>>();
BaseResponseModel<Collection<Person>> result = parser.parse(jsonText, new TypeReference<Collection<Person>>(){});

Notice that when the TypeReference instance is compiled in this case, it a type reference to the real concrete class that we expect.

You could do the same thing passing in a Class at runtime, however TypeReference is a bit more powerful because it even works when type T is a generic collection. There is some magic in the TypeReference implementation that allows it to hold onto type information that would normally be erased.

[update]

Updated to use `Collection<Person>`. Note - as far as I know as `List<Whatever>` should work also, but I double checked a project where I was using jackson to deserialize collections. Base class Collection definitely worked so I stayed with that.

Problem

i have the following problem. I have to parse a json request into an object that contains a generic type field. EDIT i have made some tests using a regular class type (so i make it work before i replace it with generic). Now parsing for a single element works great. The issue is when i need to parse out a list object out of that class. So i have to inform jackson somehow that my T is of type list instead of just AlbumModel. Here is what i have tried. ``` @Override public ListResponseModel<AlbumModel> parse(String responseBody) throws Exception { JavaType type = mapper.getTypeFactory().constructParametricType(ResponseModel.class, AlbumModel.class); return mapper.readValue(responseBody, mapper.getTypeFactory().constructParametricType(ResponseModel.class, type)); } ``` But the code above doesn't work. what is the solution for something like this? my generic type in the ListResponseModel is defined like: `List<T> data` succeeded like: ``` public class BaseResponseModel<T> { @JsonProperty("data") private T data; @JsonProperty("paginations") private PaginationModel pagination; } ``` so far i have the following code but it always parses into a Hash. ``` public class ResponseParser extends BaseJacksonMapperResponseParser<ResponseModel<AlbumModel>> { public static final String TAG = ResponseParser.class.getSimpleName(); @Override public ResponseModel<AlbumModel> parse(String responseBody) throws Exception { return mapper.readValue(responseBody, mapper.getTypeFactory().constructParametricType(ResponseModel.class, AlbumModel.class)); } } public abstract class BaseJacksonMapperResponseParser<T> implements HttpResponseParser<T> { public static final String TAG = BaseJacksonMapperResponseParser.class.getSimpleName(); public static ObjectMapper mapper = new ObjectMapper(); static { mapper.disable(Feature.FAIL_ON_UNKNOWN_PROPERTIES); mapper.enable(Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true); } } ```

Original source