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

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

问题描述

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

我生成的JSON如下,data"中的3个类都实现了CheckStatusDetail":

<代码>{错误代码":0,错误消息":空,类型":数组",数据" : [ {"@class" : "com.rrr.base.status.module.dto.DiscoveryAgentCheckStatusDetail",服务器信息":{"@class" : "com.rrr.base.util.discovery.config.xml.XMLServerInfo","name" : "java","location" : "THEO","描述": "sddgs",组":java",别名":[水银"]}}, {"@class" : "com.rrr.base.status.module.dto.MongoDBCheckStatusDetail",地址":[本地主机:27017"],版本":2.5",连接":真}, {"@class" : "com.rrr.base.status.module.dto.NetworkCheckStatusDetail",裂脑":假}],计数":3,状态":0}

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

公共类 NSResponse;实现可序列化{private static final long serialVersionUID = 1L;公共静态最终 int STATUS_OK = 0;public static final int STATUS_ERROR = -1;public static final String TYPE_OBJECT = "object";public static final String TYPE_ARRAY =数组";私有 int 状态;私人 int 错误代码;私人字符串错误消息;私有字符串类型;私人列表<T>数据;私有整数计数;公共 NSResponse() { }公共 NSResponse(int errorCode, String errorMessage) {this.status = STATUS_ERROR;this.errorCode = 错误代码;this.errorMessage = errorMessage;}公共 NSResponse(T 数据) {this.status = STATUS_OK;this.type = TYPE_OBJECT;this.data = new ArrayList();this.data.add(data);this.count = this.data.size();}公共 NSResponse(列表 数据){this.status = STATUS_OK;this.type = TYPE_ARRAY;this.data = 数据;this.count = (data == null) ?0:数据大小();}/* 省略了 getter 和 setter */}

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

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")公共接口 CheckStatusDetail 扩展了 Serializable {}

尝试在客户端使用 JSON 时,出现此错误:

java.lang.ClassCastException:java.util.LinkedHashMap 无法转换为 com.rrr.base.status.module.dto.CheckStatusDetail

当我反序列化后第一次尝试访问数据"字段时,会发生此错误.如果我调试客户端,Jackson 似乎会返回一个 List,这解释了错误,因为我期待的是 List.>

我做错了什么?

解决方案

您需要显示更多代码,特别是关于如何调用反序列化,但从错误中我猜您没有传递 T 的参数化.如果是缺少,T 只能假定为 Object 类型,并且 Object 的名义类型绑定到原生"Java 类型,对于 JSON 对象,它是 Map(特别是 LinkedHashMap 以保持顺序).

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

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

NSResponseresp = mapper.readValue(json, TypeFactory.genericType(NSResponse.class, CheckStatusDetails.class));

两者都有效;如果类型仅动态可用,则后者是必需的.

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

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
}

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

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

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

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

What am I doing wrong?

解决方案

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).

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>>() { });

or

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天全站免登陆