【问题标题】:Jackson and generic type referenceJackson 和泛型类型参考
【发布时间】:2011-10-14 08:17:32
【问题描述】:

我想使用 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<T> {
     private List<T> myobjects;
        
     public void setMyObjects(List<T> ets) {
         this.myobjects = ets;
     }

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

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

【问题讨论】:

  • 请添加getT()的实现
  • 这个问题与stackoverflow.com/questions/6062011/… 类似,但他们建议使用 TypeFactory 指定类型。但是我不知道编译时的类型...
  • TypeFactory 有不需要静态类的方法; createCollectionType 等等。
  • 请分享完整代码。我也面临同样的问题。
  • TypeReference 不是抽象的吗?

标签: java json generics jackson


【解决方案1】:

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

这种情况下,tester方法需要有Class的访问权限,可以构造

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

然后

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

【讨论】:

  • 它有效:我做了以下事情:JavaType topMost = mapper.getTypeFactory().constructParametricType(MyWrapper.class, ActualClassRuntime.class);然后做了readValue,它终于起作用了:)
  • @StaxMan 从现在开始使用 ClassMate 做这些事情会更好吗?
  • @husayt 是的,从技术上讲,java-classmate lib 更胜一筹。但是将它与 Jackson 集成有点棘手,因为 Jackson 自己的类型抽象是 API 的集成部分。从长远来看,找出让 Jackson 使用同学代码的正确方法会很棒,无论是嵌入式还是通过 dep。
  • @MartinAndersson 为什么会这样? JSON 只是数据,既没有类型(除了简单的 JSON 类型的 Lists、Maps、数字、字符串、布尔值)也没有标识。任何类型的输入都由 Java 代码解释;尽管它可以使用约定来编码类型(并且对于多态类型必须这样做),但如果调用者可以指定类型以将数据映射到,则不需要。
  • 我觉得 Jackson 不应该掩盖泛型中的空白,但无论哪种方式,它都做得很好。
【解决方案2】:

'JavaType' 有效!! 我试图将 json String 中的 List 解组(反序列化)为 ArrayList java Objects,并且从几天以来一直在努力寻找解决方案。
下面是最终给我解决方案的代码。 代码:

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?
  • 请给我看一个小例子。我正在传递 Class> 目标,然后获取 target.getClassName()。
  • 添加构造函数如下: JsonMarshallerUnmarshaller{ private Class targetClass ; JsonMarshallerUnmarshaller(Class c){ targetClass = c ;现在对“unmarshal”函数进行适当的更改以使用此类而不是在任何地方执行 getClass。
  • 几点注意事项:通过注意所有异常都是IOException 的子类型(只需要一个捕获),并且默认注释内省已经是JacksonAnnotationIntrospector,可以大大简化代码 - 所以无需对ObjectMapper 做任何事情,只需构建它即可。
  • 所以我什至无法编译这段代码。有任何实际示例可以粘贴吗?
【解决方案3】:

我修改了rushidesai1's answer 以包含一个工作示例。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 2014-05-08
    • 1970-01-01
    • 2016-05-27
    • 2013-08-16
    相关资源
    最近更新 更多