杰克逊没有反序列化它已序列化的通用列表 [英] Jackson is not deserialising a generic list that it has serialised

查看:107
本文介绍了杰克逊没有反序列化它已序列化的通用列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用Apache Jersey与Jackson进行JSON序列化时(在服务器和客户端上),我在反序列化通用List时遇到了问题。

When using Apache Jersey with Jackson for JSON serialisation (on both server and client), I'm hitting a problem when deserialising a generic List.

JSON I生产如下,数据中的所有3个类实现CheckStatusDetail:

The JSON I am producing is as follows, all 3 classes in "data" implement "CheckStatusDetail":

{
  "errorCode" : 0,
  "errorMessage" : null,
  "type" : "array",
  "data" : [ {
    "@class" : "com.rrr.base.status.module.dto.DiscoveryAgentCheckStatusDetail",
    "serverInfo" : {
      "@class" : "com.rrr.base.util.discovery.config.xml.XMLServerInfo",
      "name" : "java",
      "location" : "THEO",
      "description" : "sddgs",
      "group" : "java",
      "aliases" : [ "mercury" ]
    }
  }, {
    "@class" : "com.rrr.base.status.module.dto.MongoDBCheckStatusDetail",
    "addresses" : [ "localhost:27017" ],
    "version" : "2.5",
    "connected" : true
  }, {
    "@class" : "com.rrr.base.status.module.dto.NetworkCheckStatusDetail",
    "splitBrain" : false
  } ],
  "count" : 3,
  "status" : 0
}

生成此JSON的对象如下所示,我在客户端使用相同的类:

The object that produces this JSON looks like this, I'm using the same class on the client side:

public class NSResponse<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    public static final int STATUS_OK       = 0;
    public static final int STATUS_ERROR    = -1;

    public static final String TYPE_OBJECT  = "object";
    public static final String TYPE_ARRAY   = "array";

    private int status;
    private int errorCode;
    private String errorMessage;
    private String type;

    private List<T> data;

    private int count;

    public NSResponse() {   }

    public NSResponse(int errorCode, String errorMessage) {
        this.status = STATUS_ERROR;
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }

    public NSResponse(T data) {
        this.status = STATUS_OK;
        this.type = TYPE_OBJECT;
        this.data = new ArrayList<T>();
        this.data.add(data);
        this.count = this.data.size();
    }

    public NSResponse(List<T> data) {
        this.status = STATUS_OK;
        this.type = TYPE_ARRAY;
        this.data = data;
        this.count = (data == null) ? 0 : data.size();
    }

    /* Getters and setters omitted */
}

自从我将此注释添加到CheckStatusDetail接口后,正在应用@class信息:

The @class information is being applied since I added this annotation to my CheckStatusDetail interface:

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
public interface CheckStatusDetail extends Serializable {}

当尝试在客户端使用JSON时,我收到此错误:

When trying to consume the JSON at the client end, I get this error:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.rrr.base.status.module.dto.CheckStatusDetail

第一次尝试在反序列化后访问数据字段时会发生此错误。如果我调试客户端,杰克逊似乎正在返回列表< LinkedHashMap> ,这解释了错误,因为我期待列表< CheckStatusDetail>

This error occurs the first time I try to access the "data" field after deserialising it. If I debug the client end, Jackson seems to be returning a List<LinkedHashMap>, which explains the error, since I'm expecting a List<CheckStatusDetail>.

我做错了什么?

推荐答案

你需要多表现一点代码,特别是关于如何调用反序列化,但是从错误中我猜你不会传递T的参数化。如果缺少,T只能被假定为Object类型,而名义类型的Object被绑定为native Java类型,对于JSON对象是Map(具体而言,LinkedHashMap是为了保持顺序)。

You need to show bit more code, specifically on how you invoke deserialization, but from the error I would guess you are not passing parameterization of T. If it is missing, T can only be assumed to be of type Object, and nominal type of Object is bound to "native" Java type, which for JSON objects is Map (and specifically, LinkedHashMap to preserve order).

所以你可能只需要在反序列化时指定泛型类型的对象(对于序列化不需要,因为运行时类型可用);通过使用TypeReference(不是普通的Class,因为它没有泛型类型信息),或者通过构造泛型的JavaType。例如:

So you probably just need to specify generic type of object on deserialization (for serialization it is not needed as runtime type is available); either by using TypeReference (not plain Class, since that has no generic type info), or by constructing generic-enabled JavaType. For example:

NSResponse<CheckStatusDetail> resp = mapper.readValue(json, new TypeReference<NSResponse<CheckStatusDetail>>() { });

NSResponse<CheckStatusDetail> resp = mapper.readValue(json, TypeFactory.genericType(NSResponse.class, CheckStatusDetails.class));

两者都有效;如果类型只是动态可用,则后者是必要的。

both work; latter is necessary if type is only dynamically available.

这篇关于杰克逊没有反序列化它已序列化的通用列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆