You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Jackson使用JsonSubTypes时父类字段反序列化失败

解决Jackson多态反序列化时父类type字段为null的问题

我定义了如下Java类,使用Jackson实现多态反序列化:

public class TestClass {

    public ParentClass parentClass;

    public ParentClass getParentClass() {
        return parentClass;
    }

    public void setParentClass(ParentClass parentClass) {
        this.parentClass = parentClass;
    }

    @Override
    public String toString() {
        return "TestClass [parentClass=" + parentClass + "]";
    }

}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = ChildClass1.class, name = "childClass1"),
        @JsonSubTypes.Type(value = ChildClass2.class, name = "childClass2")
})
public class ParentClass {

    @JsonProperty
    public String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "ParentClass [type=" + type + "]";
    }

}

public class ChildClass1 extends ParentClass {
    public String childClass1Field;

    public String getChildClass1Field() {
        return childClass1Field;
    }

    public void setChildClass1Field(String childClass1Field) {
        this.childClass1Field = childClass1Field;
    }

    @Override
    public String toString() {
        return "ChildClass1 [childClass1Field=" + childClass1Field + ", type=" + type + "]";
    }


}

public class ChildClass2 extends ParentClass {
    public String childClass2Field;

    public String getChildClass2Field() {
        return childClass2Field;
    }

    public void setChildClass2Field(String childClass2Field) {
        this.childClass2Field = childClass2Field;
    }

    @Override
    public String toString() {
        return "ChildClass2 [childClass2Field=" + childClass2Field + ", type=" + type + "]";
    }
}

当反序列化以下JSON负载时:

[{
  "parentClass": {
      "type": "childClass1",
      "childClass1Field": "my child class 1 field value"
  }
}]

得到的对象输出为:

[TestClass [parentClass=ChildClass1 [childClass1Field=my child class 1 field value, type=null]]]

多态实例化功能正常,已正确创建ChildClass1实例,但父类的type字段始终为null,而非预期的childClass1。


原因分析

Jackson的@JsonTypeInfo注解默认会消耗用于类型识别的字段(此处为type),仅用它来判断实例化哪个子类,不会再将该字段的值反序列化到类的对应属性中,这就是type字段为null的核心原因。

解决方法

方法1:配置visible = true保留类型字段

修改ParentClass上的@JsonTypeInfo注解,添加visible = true参数,让Jackson在完成类型识别后,仍将该字段的值反序列化到类属性中:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = ChildClass1.class, name = "childClass1"),
        @JsonSubTypes.Type(value = ChildClass2.class, name = "childClass2")
})
public class ParentClass {
    // 原有代码无需修改
}

方法2:分离类型识别字段与类属性名

如果不想修改@JsonTypeInfo的默认行为,可以将类中的属性名与JSON里的类型识别字段名区分开,比如把类中的type改为typeName,通过@JsonProperty映射JSON中的type字段:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = ChildClass1.class, name = "childClass1"),
        @JsonSubTypes.Type(value = ChildClass2.class, name = "childClass2")
})
public class ParentClass {
    @JsonProperty("type")
    public String typeName;

    public String getTypeName() {
        return typeName;
    }

    public void setTypeName(String typeName) {
        this.typeName = typeName;
    }

    @Override
    public String toString() {
        return "ParentClass [type=" + typeName + "]";
    }
}

同时需要修改子类的toString方法,将引用的type替换为typeName。

内容的提问来源于stack exchange,提问作者ustad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:43:32