杰克逊没有反序列化它已经序列化的通用列表

sea*_*ges 16 java serialization json jersey jackson

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

我生成的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
}
Run Code Online (Sandbox Code Playgroud)

生成此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 */
}
Run Code Online (Sandbox Code Playgroud)

由于我将此注释添加到CheckStatusDetail接口,因此正在应用@class信息:

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

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

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.rrr.base.status.module.dto.CheckStatusDetail
Run Code Online (Sandbox Code Playgroud)

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

我究竟做错了什么?

Sta*_*Man 29

你需要显示更多的代码,特别是你如何调用反序列化,但从错误中我猜你不会传递T的参数化.如果缺少,T只能被假定为Object类型,名义类型为对象绑定到"本机"Java类型,对于JSON对象是Map(具体而言,LinkedHashMap保留顺序).

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

NSResponse<CheckStatusDetail> resp = mapper.readValue(json, new TypeReference<NSResponse<CheckStatusDetail>>() { });
Run Code Online (Sandbox Code Playgroud)

要么

NSResponse<CheckStatusDetail> resp = mapper.readValue(json, TypeFactory.genericType(NSResponse.class, CheckStatusDetails.class));
Run Code Online (Sandbox Code Playgroud)

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

  • 不推荐使用TypeFactory,只是它的静态方法.所以你需要找一个实例; 最常见的是使用ObjectMapper.getTypeFactory(). (3认同)