如何通过未知 属性 的 JsonTypeInfo 反序列化 JSON

How to deserialize JSON via JsonTypeInfo with unknown property

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

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

为了反序列化我上面写的 JSON 我创建了几个 classes:

@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

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

我该如何解决这个问题?

总结

目前尚不清楚问题的确切根本原因是什么,因为您的示例经过多次更正后对我有效。

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

更正

根对象的数据class:已引入

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 数据 class:更新为反序列化 type 属性

请参阅 the Javadoc:

Note on visibility of type identifier: by default, deserialization (use during reading of JSON) of type identifier is completely handled by Jackson, and is not passed to deserializers. However, if so desired, it is possible to define property visible = true in which case property will be passed as-is to deserializers (and set via setter or field) on deserialization.

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

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

此外,请参阅相关问题:

数据classes:实现toString()方法

(略)

主要:更新为使用根数据class

请注意,我已更正 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']]]

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