Jackson and generic type reference Jackson and generic type reference json json

Jackson and generic type reference


This is a well-known problem with Java type erasure: T is just a type variable, and you must indicate actual class, usually as Class argument. Without such information, best that can be done is to use bounds; and plain T is roughly same as 'T extends Object'. And Jackson will then bind JSON Objects as Maps.

In this case, tester method needs to have access to Class, and you can construct

JavaType type = mapper.getTypeFactory().  constructCollectionType(List.class, Foo.class)

and then

List<Foo> list = mapper.readValue(new File("input.json"), type);


'JavaType' works !! I was trying to unmarshall (deserialize) a List in json String to ArrayList java Objects and was struggling to find a solution since days.
Below is the code that finally gave me solution. Code:

JsonMarshallerUnmarshaller<T> {    T targetClass;    public ArrayList<T> unmarshal(String jsonString) {        ObjectMapper mapper = new ObjectMapper();        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();        mapper.getDeserializationConfig()            .withAnnotationIntrospector(introspector);        mapper.getSerializationConfig()            .withAnnotationIntrospector(introspector);        JavaType type = mapper.getTypeFactory().            constructCollectionType(                ArrayList.class,                 targetclass.getClass());        try {            Class c1 = this.targetclass.getClass();            Class c2 = this.targetclass1.getClass();            ArrayList<T> temp = (ArrayList<T>)                 mapper.readValue(jsonString,  type);            return temp ;        } catch (JsonParseException e) {            e.printStackTrace();        } catch (JsonMappingException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        return null ;    }  }


I modified rushidesai1's answer to include a working example.

JsonMarshaller.java

import java.io.*;import java.util.*;public class JsonMarshaller<T> {    private static ClassLoader loader = JsonMarshaller.class.getClassLoader();    public static void main(String[] args) {        try {            JsonMarshallerUnmarshaller<Station> marshaller = new JsonMarshallerUnmarshaller<>(Station.class);            String jsonString = read(loader.getResourceAsStream("data.json"));            List<Station> stations = marshaller.unmarshal(jsonString);            stations.forEach(System.out::println);            System.out.println(marshaller.marshal(stations));        } catch (IOException e) {            e.printStackTrace();        }    }    @SuppressWarnings("resource")    public static String read(InputStream ios) {        return new Scanner(ios).useDelimiter("\\A").next(); // Read the entire file    }}

Output

Station [id=123, title=my title, name=my name]Station [id=456, title=my title 2, name=my name 2][{"id":123,"title":"my title","name":"my name"},{"id":456,"title":"my title 2","name":"my name 2"}]

JsonMarshallerUnmarshaller.java

import java.io.*;import java.util.List;import com.fasterxml.jackson.core.*;import com.fasterxml.jackson.databind.*;import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;public class JsonMarshallerUnmarshaller<T> {    private ObjectMapper mapper;    private Class<T> targetClass;    public JsonMarshallerUnmarshaller(Class<T> targetClass) {        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();        mapper = new ObjectMapper();        mapper.getDeserializationConfig().with(introspector);        mapper.getSerializationConfig().with(introspector);        this.targetClass = targetClass;    }    public List<T> unmarshal(String jsonString) throws JsonParseException, JsonMappingException, IOException {        return parseList(jsonString, mapper, targetClass);    }    public String marshal(List<T> list) throws JsonProcessingException {        return mapper.writeValueAsString(list);    }    public static <E> List<E> parseList(String str, ObjectMapper mapper, Class<E> clazz)            throws JsonParseException, JsonMappingException, IOException {        return mapper.readValue(str, listType(mapper, clazz));    }    public static <E> List<E> parseList(InputStream is, ObjectMapper mapper, Class<E> clazz)            throws JsonParseException, JsonMappingException, IOException {        return mapper.readValue(is, listType(mapper, clazz));    }    public static <E> JavaType listType(ObjectMapper mapper, Class<E> clazz) {        return mapper.getTypeFactory().constructCollectionType(List.class, clazz);    }}

Station.java

public class Station {    private long id;    private String title;    private String name;    public long getId() {        return id;    }    public void setId(long id) {        this.id = id;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return String.format("Station [id=%s, title=%s, name=%s]", id, title, name);    }}

data.json

[{  "id": 123,  "title": "my title",  "name": "my name"}, {  "id": 456,  "title": "my title 2",  "name": "my name 2"}]