杰克逊无法读取在超类中声明的字段



我有这个父类:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "objectType")
@JsonSubTypes(
{
@JsonSubTypes.Type(value = Child.class, name = "child"),
}
)
public class Parent {
@JsonProperty("objectType")
private ProductType productType
public ProductType getProductType { return productType; }
}

此类由子类扩展:

public class Child extends Parent {
@JsonProperty("field1")
private Field1 field1;
@JsonProperty("field2")
private Field2 field2;
}

我尝试解析以下表示Child类序列化实例的 Json 文件:

{
"objectType" : "child1",
"field1" : "value1",
"field2" : "value2"
}

。使用以下代码:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping();
Parent parent = objectMapper.treeToValue(parentJsonNode, Parent.class);

(附言parentJsonNode是通过读取 JSON 文件创建的JsonNode(。

发生的情况是,我的对象的field1field2被正确读取和设置,但是字段objectType(声明到父类中(在解析后仍然null

我应该怎么做才能让杰克逊从 Json 对象中正确读取objectType的值child

这是ProductType的代码:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ProductType {
CHILD1("child1"), CHILD2("child2");
private String objectType;
private ProductType(String objectType) {
this.objectType = objectType;
}
@JsonValue
public String getObjectType() {  return objectType; }
}

这是由于杰克逊的奇怪行为,即在编译时添加一个对您不明确可见的额外字段,以区分命名的子类,例如您在@JsonTypeInfo中输入的值。因为您的父类包含序列化为名为objectType的 JSON 属性的属性,并且@JsonTypeInfo中给出的分母的名称也objectType。如果要序列化Child的对象,您会注意到序列化的对象包含两个同名的字段objectType其中只有一个将被填充:

System.out.println(objectMapper.writeValueAsString(new Child()));

导致

{"objectType":"child","objectType":null,"field1":null,"field2":null}

解决方法是,如果在代码中不需要显式字段productType(序列化为objectType(,则跳过父类中的显式字段,或者为其指定不同的序列化名称(例如productType(,但是您当然需要将第二个 JSON 字段反序列化到其中:

改变

public class Parent {
@JsonProperty("objectType")
private String productType;

public class Parent {
@JsonProperty("productType")
private String productType;

Parent parent = objectMapper.treeToValue(objectMapper.readTree("{n" +
"    "objectType" : "child",n" +
"    "productType" : "child",n" +
"    "field1" : "value1",n" +
"    "field2" : "value2"n" +
"}"), Parent.class);
System.out.println(parent.getProductType());

导致输出

child

第三种可能性是显式初始化字段,例如通过构造函数,因为 Jackson 使用默认构造函数在反序列化时创建对象:

// For subclasses
protected Parent (String productType) {
this.productType = productType;
}
// For Jackson
public Parent () {
}

public Child () {
super("child");
}

编辑:我使用String而不是ProductType来简化我的代码,但结果是相似的。

最新更新