首页 > 解决方案 > 通过字段进行杰克逊多态反序列化

问题描述

比方说,我有一堂课

public class A{
  private UUID typeId;
  private B data;
}

public abstract class B{
  private String a;
}

public class BChildOne extends B{
  ... some variables
}

public class BChildTwo  extends B{
  ... some variables
}

B 类的类型在变化,根据 A 的 typeId ,所以如果 A 的 typeId 为“XXX”,则数据字段的类型为 BChildOne,如果 A 的 typeId 为“YYY”,则数据字段的类型为 BChildTwo。

我怎样才能做到这一点?

所以我试过了;

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility =
JsonAutoDetect.Visibility.NONE, setterVisibility = 
JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
JsonTypeInfo.As.EXTERNAL_PROPERTY , property = "typeId")
@JsonSubTypes({
 @JsonSubTypes.Type(value = BChildOne.class, name = "40ad2fe6-e672-4f0e- 
986e- 
 619c7a1a3223") }
 )
 public abstract class B{

但我收到以下错误;

意外的令牌 (END_OBJECT),预期的 FIELD_NAME:缺少包含类型 ID 的属性“typeId”(对于 B 类)

这很明显,因为 typeId 字段在 A 类而不是 B 类中。

标签: javajacksondeserializationfasterxml

解决方案


假设您的 JSON 文档如下所示:

{
  "type": "foo",
  "data": {
    "someCommonProperty": "common property",
    "fooProperty": "foo specific property"
  }
}
{
  "type": "bar",
  "data": {
    "someCommonProperty": "common property",
    "barProperty": "bar specific property"
  }
}

您可以使用:

public class Wrapper {

    private String type;

    @JsonTypeInfo(use = Id.NAME, property = "type", include = As.EXTERNAL_PROPERTY)
    @JsonSubTypes(value = { 
        @JsonSubTypes.Type(value = Foo.class, name = "foo"),
        @JsonSubTypes.Type(value = Bar.class, name = "bar") 
    })
    private AbstractData data;

    // Getters and setters
}
public abstract class AbstractData {

    private String someCommonProperty;

    // Getters and setters
}
public class Foo extends AbstractData {

    private String fooProperty;

    // Getters and setters
}
public class Bar extends AbstractData {

    private String barProperty;

    // Getters and setters
}

在这种方法中,@JsonTypeInfo设置为使用type外部属性来确定正确的类来映射data属性。JSON文档可以反序列化如下:

ObjectMapper mapper = new ObjectMapper();
Wrapper wrapper = mapper.readValue(json, Wrapper.class);  

推荐阅读