jackson通过@jsontypeinfo与@jsonsubtypes在抽象基类上实现多态反序列化,需确保类型字段存在且注解加于基类;嵌套抽象字段须在对应抽象类上重复配置;泛型集合不支持直接多态,应封装或使用deduction;建议设defaultimpl和visible增强安全与调试能力。

直接在抽象基类上用 @JsonTypeInfo 配合 @JsonSubTypes,就能让 Jackson 根据 JSON 中的类型标识字段(比如 "type" 或 "method")自动选择对应子类完成反序列化。关键不是“怎么写注解”,而是类型信息必须能被 Jackson 准确感知到——尤其当结构嵌套或含集合时,容易漏掉某一层。
基础配置:基类加注解,子类注册映射
这是最常见也最核心的用法。注解必须加在抽象父类(或接口)上,不能只加在字段或方法上(除非你明确想覆盖全局行为)。
- @JsonTypeInfo 定义类型识别方式:指定用哪个字段存类型名、字段放哪儿、怎么取值
- @JsonSubTypes 列出所有合法子类及其对应 JSON 中的标识值
示例:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
abstract class Animal {
String name;
}
对应 JSON:{"type":"dog","name":"Buddy"} → 反序列化为 Dog 实例。
嵌套抽象字段:多态必须下沉到字段层级
如果抽象类里有个字段本身也是抽象类型(比如 AbstractResult result),仅给外层类加注解是不够的。Jackson 不会自动递归识别内部字段的子类。
- 错误做法:只在外层类(如
Response)上配@JsonTypeInfo,而result字段类型仍是AbstractResult - 正确做法:把
@JsonTypeInfo和@JsonSubTypes直接加到AbstractResult类上,确保它自己能识别子类 - JSON 中该字段需携带类型字段(如
"__type": "Method01Result"),或复用已有字段(如"request_name")并设property = "request_name"
泛型集合(List)不能直接标注多态
别试图在 List<animal></animal> 字段上直接加 @JsonTypeInfo(include = As.EXTERNAL_PROPERTY) —— Jackson 不支持对泛型集合做外部属性驱动的多态解析,会报 MismatchedInputException。
- 根本原因:集合是容器,没有具体实现类可实例化;Jackson 需要一个“可实例化的类型”来匹配
- 解决方案:把多态逻辑移到封装类上。例如定义
AnimalWrapper类,给它加@JsonTypeInfo,再让 JSON 数组每个元素都带类型字段 - 或者改用
@JsonTypeInfo(use = Id.DEDUCTION)(2.12+),让 Jackson 基于字段存在性自动推断,但需确保子类结构差异明显
安全与兼容:defaultImpl 和 visible 设置
生产环境建议加上容错和可见性控制:
-
defaultImpl = DefaultAnimal.class:当 JSON 中类型名不匹配任何注册子类时,降级使用默认实现,避免崩溃 -
visible = true:让类型字段(如"type")在反序列化后仍保留在对象中,方便后续逻辑判断或日志追踪 - Jackson 2.16 默认启用白名单机制,未注册的类不会被实例化,无需额外配置也能防反序列化漏洞
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











