本文解决 spring boot 中使用 jackson 的 @jsonsubtypes 进行多态反序列化时,父类中用于类型标识的字段(如 type)值为 null 的问题,核心在于正确配置 @jsontypeinfo 的 include 和 visible 属性。
本文解决 spring boot 中使用 jackson 的 @jsonsubtypes 进行多态反序列化时,父类中用于类型标识的字段(如 type)值为 null 的问题,核心在于正确配置 @jsontypeinfo 的 include 和 visible 属性。
在 Spring Boot 应用中,当使用 Jackson 实现基于类型的多态反序列化(如通过 @JsonTypeInfo + @JsonSubTypes),一个常见陷阱是:子类实例能被正确创建,但父类中声明的类型标识字段(例如 type)却始终为 null。这并非 Jackson 无法识别类型,而是默认行为未将类型信息写入目标字段。
根本原因在于:Jackson 默认将类型信息作为额外元数据注入(如添加 "type": "childClass1" 到 JSON 外层),而非赋值给 Java 字段。即使你在父类中定义了 type 字段并标注 @JsonProperty,若未显式告知 Jackson “该字段既用于类型识别,也需参与反序列化”,它就不会将解析出的类型名写入该字段。
✅ 正确解法是修改 @JsonTypeInfo 注解,启用 EXISTING_PROPERTY 模式并设 visible = true:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY, // 关键:复用已存在字段,而非新增
property = "type",
visible = true // 关键:使 type 字段对反序列化器可见(即允许写入)
)
@JsonSubTypes({
@JsonSubTypes.Type(value = ChildClass1.class, name = "childClass1"),
@JsonSubTypes.Type(value = ChildClass2.class, name = "childClass2")
})
public class ParentClass {
protected String type; // 注意:建议使用 protected 或 package-private,避免 public 引发意外覆盖
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}⚠️ 注意事项:
- include = As.EXISTING_PROPERTY 表示 Jackson 将从 JSON 中读取 "type" 字段的值,并赋给 ParentClass.type,同时依据该值决定实例化哪个子类;
- visible = true 是必需的——它告诉 Jackson:该 type 字段不仅是类型标识符,也是普通业务字段,需参与反序列化流程(否则即使字段存在,也不会被赋值);
- 父类中的 type 字段不应再额外加 @JsonProperty("type")(可能引发重复绑定),Jackson 会自动处理;
- 子类中无需重写 type 字段或 setter/getter,继承即可;
- 若使用 Lombok,建议对 ParentClass 使用 @Getter @Setter 而非 @Data(避免 @Data 自动生成的 equals/hashCode 意外包含 type 导致逻辑异常)。
完整验证示例(Spring Boot 环境下):
// 测试反序列化
String json = """
{
"parentClass": {
"type": "childClass1",
"childClass1Field": "my child class 1 field value"
}
}
""";
TestClass testObj = new ObjectMapper().readValue(json, TestClass.class);
System.out.println(testObj);
// 输出:TestClass [parentClass=ChildClass1 [childClass1Field=my child class 1 field value, type=childClass1]]? 总结:Jackson 多态反序列化的字段空值问题,本质是类型信息与业务字段的绑定配置缺失。只需两处关键调整——include = EXISTING_PROPERTY 和 visible = true——即可让 type 字段既驱动多态,又承载业务值,实现语义与功能的统一。

















