Jackson和泛型参考


107

我想将jackson json库用于通用方法,如下所示:

public MyRequest<T> tester() {
    TypeReference<MyWrapper<T>> typeRef = new TypeReference<MyWrapper<T>>();  
    MyWrapper<T> requestWrapper = (MyWrapper<T>) JsonConverter.fromJson(jsonRequest, typeRef);
    return requestWrapper.getRequest();
}

...

public class MyWrapper<T> {

    private MyRequest<T> request;

    public MyRequest<T> getRequest() {
        return request;
    }

    public void setRequest(MyRequest<T> request) {
        this.request = request;
    }
}


 public class MyRequest{
     private List<T> myobjects;

     public void setMyObjects(List<T> ets) {
         this.myobjects = ets;
     }

     @NotNull
     @JsonIgnore
     public T getMyObject() {
         return myobjects.get(0);
     }
}

现在的问题是,当我调用请求对象内的getMyObject()时,杰克逊将嵌套的自定义对象作为LinkedHashMap返回。有什么方法可以指定需要返回T对象吗?例如:如果我发送了类型为Customer的对象,则应该从该List?中返回Customer。

谢谢。


请添加getT()的实现
Jim Garrison

这个问题类似于stackoverflow.com/questions/6062011/…,但是他们建议使用TypeFactory指定类型。但是我不知道在编译时的类型...
techzen 2011年

TypeFactory的方法不需要静态类。createCollectionType等。
StaxMan 2011年

请分享完整的代码。我也面临着同样的问题。
AZ_

不是TypeReference抽象的吗?
凯尔·德莱尼

Answers:


194

这是Java类型擦除的一个众所周知的问题:T只是一个类型变量,您必须指示实际的类,通常将其作为Class参数。没有这些信息,最好的办法就是使用界限。普通T与“ T扩展对象”大致相同。然后Jackson会将JSON对象绑定为Maps。

在这种情况下,tester方法需要访问Class,并且您可以构造

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

然后

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

16
它的工作原理:我做了以下工作:JavaType topMost = mapper.getTypeFactory()。constructParametricType(MyWrapper.class,ActualClassRuntime.class); 然后执行了readValue,它终于起作用了:)
techzen 2011年

是的,这确实有效-感谢您指出创建Map / Collection类型以外的泛型类型的方法!
StaxMan

1
@StaxMan从现在开始将ClassMate用于此类事情会更好吗?
侯赛特2014年

2
@husayt是的,从技术上讲,java-classmate lib是更好的。但是将其与Jackson集成起来有点棘手,因为Jackson自己的类型抽象是API的集成部分。从长远来看,最好找到使Jackson使用嵌入式或通过dep的同学代码的正确方法。
StaxMan 2014年

1
我觉得杰克逊(Jackson)不必掩盖仿制药方面的空白,但是无论哪种方式,它都做得很好。
阿德里安·贝克

6

“ JavaType”有效!我试图将json字符串中的列表解组(反序列化)到ArrayList java对象,并且从现在开始一直在努力寻找解决方案。
下面是最终给我解决方案的代码。码:

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 ;
    }  
}

如何初始化TargetClass?
AZ_

请给我举个小例子。我正在传递Class <?>目标,然后获得target.getClassName()。
2013年

1
添加如下构造函数:JsonMarshallerUnmarshaller <T> {private Class <T> targetClass; JsonMarshallerUnmarshaller(Class <T> c){targetClass = c; 现在,对“ unmarshal”函数进行适当的更改,以使用此类而不是在所有地方都使用getClass。
rushidesai1 2013年

几个注意事项:可以注意到所有异常都是的子类型IOException(只需一个捕获),并且可以使用默认注释自省内窥镜JacksonAnnotationIntrospector,因此可以简化很多代码,因此无需进行任何操作ObjectMapper,只需对其进行构造即可。
StaxMan

所以这段代码我什至没有编译。有任何现场示例可以替代吗?
扳手

0

我修改了rushidesai1的答案,以包含一个有效的示例。

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
    }
}

输出量

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"
}]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.