【问题标题】:Jackson can't deserialize JSON it serializes with enableDefaultTyping()Jackson 无法反序列化它使用 enableDefaultTyping() 序列化的 JSON
【发布时间】:2018-12-16 09:39:01
【问题描述】:

使用 Jackson 2.9.5,我将对象序列化为 JSON 并将其反序列化回 Java 对象。在反序列化 JSON 时,Jackson 抛出此异常:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of 'com.xxx.models.Header' out of START_ARRAY token
     at [Source: (String)"{
      "header" : [ "com.xxx.models.Header", {
        "sourceAddress" : 0,
        "destinationAddress" : 1, ...

这是半可以理解的,因为反序列化的 JSON 看起来像这样:

{
  "header" : [ "com.xxx.models.Header", {
    "sourceAddress" : 0,
    "destinationAddress" : 1
]}

Jackson 在使用mapper.enableDefaultTyping()mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE)mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS) 并调用writeValueAsString() 时添加数组语法。

但是在同一个对象映射器上调用 readValue() 来反序列化它刚刚生成的同一个 JSON 会引发上述异常。为什么? 我做错了什么?

我应该注意,如果我去掉添加的 [ "com.xxx.models.Header", 位(及其对应的数组终止符),JSON 将按预期进行解析,并且反序列化的对象已完全填充。

这似乎与多态性特别相关,所以这里是对象定义。 SerialMessage 包含 IHeaderIPayloadHeader 扩展了实现 IHeaderAbstractHeader,这是我正在序列化但无法反序列化的内容。

public class SerialMessage {

    private IHeader header;
    private IPayload payload;

    public SerialMessage() {};
    public SerialMessage(IHeader header) {
        this.header = header;
    }

    public SerialMessage(IHeader header, IPayload payload) {
        this(header);
        this.payload = payload;
    };

    public IHeader getHeader() {
        return header;
    }
    public void setHeader(Header header) {
        this.header = header;
    }
    public IPayload getPayload() {
        return payload;
    }
    public void setPayload(IPayload payload) {
        this.payload = payload;
    }
}

.

public class AbstractHeader implements IHeader {

    protected short sourceAddress;
    protected short destinationAddress;

    public short getSourceAddress() {
        return sourceAddress;
    }

    public void setSourceAddress(short sourceAddress) {
        this.sourceAddress = sourceAddress;
    }

    public short getDestinationAddress() {
        return destinationAddress;
    }

    public void setDestinationAddress(short destinationAddress) {
        this.destinationAddress = destinationAddress;
    }
}

.

public class Header extends AbstractHeader {
}

【问题讨论】:

  • 你的 json 格式不正确,应该是 [{"key":"value"}]
  • @GauravSrivastav 我认为只有字符串值才能在 JSON 中引用。在我的情况下,这些值是数字。
  • “标题”怎么样:[“com.xxx.models.Header”,{...
  • @GauravSrivastav Jackson 在使用 mapper.enableDefaultTyping() 时添加了数组语法。它应该允许 Jackson 识别 JSON 应该被反序列化为哪个具体的类类型。

标签: java jackson


【解决方案1】:

这是使用 enableDefaultTyping()mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE)mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS) 反序列化 Jackson 序列化对象的一贯问题。

根本原因似乎是 Jackson 根本不理解从这些选项生成的自己的包装语法。经过大量实验,Jackson 只能反序列化它已经序列化的对象层次结构(来自问题)如果对象使用 @JsonType 注释。

在问题所示的情况下,接口IHeader可以注释为:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
public interface IHeader {
...
}

生成 JSON

{
  "header" : {
    "@class" : "com.xxx.models.Header",
    "sourceAddress" : 0,
    "destinationAddress" : 1
}

而不是用数组语法包装每个对象以指示其实现类型。

我无法找到告诉ObjectMapper 使用等效的 JsonTypeInfo.As.PROPERTY 的方法。用@JsonType 注释每个接口并不理想,但确实可以解决原始问题。

https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization#12-per-class-annotations 上查看Jackson 的@JsonType 文档。

【讨论】:

    【解决方案2】:
        public IHeader getHeader() {
            return header;
        }
        public void setHeader(Header header) {
            this.header = header;
        }
    

    问题的原因是header字段的getter返回了Interface类型的IHeader,但是setter的具体类型是Header。 JSON序列化时,header字段的类型由它的getter决定,即IHeaderIHeader是多态类型。 JSON反序列化时,header字段的类型由其setter的参数类型决定,即HeaderHeader是具体类型。所以此时,Jackson 会抛出此消息的异常。

    “无法从 START_ARRAY 令牌中反序列化 xxx 实例”

    更多详情可以参考com.fasterxml.jackson.databind.ser.BeanSerializerFactory#_constructWritercom.fasterxml.jackson.databind.deser.BeanDeserializerFactory#addBeanProps

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-02
      • 2023-03-04
      • 2014-08-02
      • 2013-01-08
      • 1970-01-01
      • 2016-04-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多