Jackson 没有反序列化已序列化的通用列表

Posted

技术标签:

【中文标题】Jackson 没有反序列化已序列化的通用列表【英文标题】:Jackson is not deserialising a generic list that it has serialised 【发布时间】:2011-08-29 01:17:44 【问题描述】:

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

我生成的 JSON 如下,“data”中的所有 3 个类都实现了“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 的对象如下所示,我在客户端使用相同的类:

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 信息正在被应用:

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

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

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

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

我做错了什么?

【问题讨论】:

【参考方案1】:

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

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

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

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

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

【讨论】:

太好了,我不得不以稍微不同的方式使用 TypeFactory:“TypeFactory.type(NSResponse.class, CheckStatusDetails.class)”,但可能是版本不匹配,结果正是我想要的。谢谢! 是的,我没有检查确切的方法名称(加上 1.8 确实有微小的变化),但重要的是你让它工作。 :) @seanhodges TypeFactory.type 已弃用 使用什么? TypeFactory 没有被弃用,只是它的静态方法。所以你需要找到一个实例;最常见的是使用 ObjectMapper.getTypeFactory()。 哇,这个解决方案对我来说真的很棒!它帮助我在我的 Java 应用程序中动态处理从 Facebook 的 Graph API 接收的 JSON 数组数据,并将数据反序列化为适当对象的数组。

以上是关于Jackson 没有反序列化已序列化的通用列表的主要内容,如果未能解决你的问题,请参考以下文章

Jackson xml反序列化 - 序列化为一个列表,其中包含任意元素

2:如何反序迭代一个序列(字符串,列表,元组)

使用 Jackson 反序列化对象列表

使用 Jackson 反序列化:获取 Json 对象设置的字段列表

Jackson - 将内部对象列表反序列化为更高级别的列表

无法使用 Jackson XML 直接在根元素内反序列化列表