杰克逊无法反序列化使用enableDefaultTyping()

时间:2018-07-08 14:44:38

标签: java jackson

使用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
]}

当使用mapper.enableDefaultTyping()mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE)mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS)并调用writeValueAsString()时,杰克逊添加了数组语法。

但是在同一对象映射器上调用readValue()以反序列化 just 生成的同一JSON会抛出上述异常。为什么? 我在做什么错了?

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

这似乎与多态性特别相关,因此这里是对象定义。 SerialMessage包含一个IHeaderIPayloadHeader扩展了实现AbstractHeader的{​​{1}},这是我要序列化且不能反序列化的内容。

IHeader

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

1 个答案:

答案 0 :(得分:0)

使用enableDefaultTyping()mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE)mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS)反序列化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文档。