【问题标题】:How to deserialize JSON via JsonTypeInfo with unknown property如何通过具有未知属性的 JsonTypeInfo 反序列化 JSON
【发布时间】:2022-01-26 21:05:44
【问题描述】:

我需要反序列化的 JSON 如下所示:

{
  "data": [{
    "id": "id1",
    "type": "type1"
    "name": "John",
    ...
  },
  {
    "id": "id2",
    "type": "type2",
    "name": "Rebecca",
    ...
  },
  {
    "id": "id3",
    "type": "unknown",
    "name": "Peter",
    ...
  }]
}

为了对上面写的 JSON 进行反序列化,我创建了几个类:

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        property = "type",
        defaultImpl = DefaultData.class
)
@JsonSubTypes({
        @JsonSubTypes.Type(value = Type1Data.class, name = "type1"),
        @JsonSubTypes.Type(value = Type2Data.class, name = "type2")
})
public class AbstractData {
    public final String id;
    public final String type;
    public final String name;
    public AbstractData(String id, String type, String name) {
        this.id = id;
        this.type = type;
        this.name = name;
    }
}

public class Type1Data extends AbstractData {
    @JsonCreator
    public Type1Data(@JsonProperty("id") String id,
                     @JsonProperty("name") String name
    ) {
        super(id, "type1", name);
    }
}

public class DefaultData extends AbstractData {
    @JsonCreator
    public DefaultData(@JsonProperty("id") String id, 
                       @JsonProperty("type") String type,
                       @JsonProperty("name") String name
    ) {
        super(id, type, name);
    }
}

public class Main {
    public static void main(String... args) {
        ObjectMapper mapper = new ObjectMapper();
        AbstractData data = mapper.readValue(json, AbstractData.class);
    }
}

如果我使用默认实现,我会得到一个异常:

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'unknown' as a type

DefaultData 类如果我会得到未知类型,我需要避免反序列化异常。

我该如何解决这个问题?

【问题讨论】:

  • 使用的是哪个版本的 Jackson?
  • @SergeyVyacheslavovichBrunov 我使用2.10.2 版本。

标签: java json jackson jackson-databind


【解决方案1】:

总结

目前尚不清楚问题的确切根本原因是什么,因为您的示例对我有用,并进行了一些更正。

不过,请将更正视为草稿。

更正

根对象的数据类:引入

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays;
import java.util.StringJoiner;

public class RootData {
    public final AbstractData[] data;

    @JsonCreator
    public RootData(@JsonProperty("data") final AbstractData[] data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return new StringJoiner(", ", RootData.class.getSimpleName() + "[", "]")
            .add("data=" + Arrays.toString(data))
            .toString();
    }
}

AbstractData 数据类:更新为反序列化 type 属性

请看the Javadoc:

关于类型标识符可见性的注意事项:默认情况下,类型标识符的反序列化(在读取 JSON 期间使用)完全由 Jackson 处理,并且不会传递给反序列化器。但是,如果需要,可以定义属性 visible = true,在这种情况下,属性将在反序列化时按原样传递给反序列化器(并通过 setter 或字段设置)。

通过添加visible = true更新注释:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    property = "type",
    visible = true,
    defaultImpl = DefaultData.class
)

另外,请参阅相关问题:java - Jackson - @JsonTypeInfo property is being mapped as null?

数据类:实现toString()方法

(省略。)

Main:更新为使用根数据类

请注意,我已更正 JSON 文档:在 "type": "type1" 之后添加了缺少的逗号。

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String... args) throws JsonProcessingException {
        final String jsonDocumentString =
            """
            {
              "data": [{
                "id": "id1",
                "type": "type1",
                "name": "John"
              },
              {
                "id": "id2",
                "type": "type2",
                "name": "Rebecca"
              },
              {
                "id": "id3",
                "type": "unknown",
                "name": "Peter"
              }]
            }
            """;

        final ObjectMapper mapper = new ObjectMapper();
        final RootData rootData = mapper.readValue(jsonDocumentString, RootData.class);
        System.out.println(rootData);
    }
}

程序成功完成,即没有抛出异常。
程序输出:

RootData[data=[Type1Data[id='id1', type='type1', name='John'], Type2Data[id='id2', type='type2', name='Rebecca'], AbstractData[id='id3', type='unknown', name='Peter']]]

实际结果(输出)与预期结果相同。

【讨论】:

  • 但在您的回复AbstractData[id='id3', type='null', name='Peter']] 中,type 属性为空,但我想得到type 等于unknown 的值。
  • @John,好消息!对不起。请查看更新后的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-19
  • 1970-01-01
  • 1970-01-01
  • 2013-07-15
  • 2012-12-09
  • 1970-01-01
相关资源
最近更新 更多