多抽象类层级下Jackson多态反序列化配置问题
多层级多态Jackson反序列化问题
类层级结构
- AbstractParent 是顶层抽象类
- AbstractChild 继承自 AbstractParent(存在1到n个子类)
- ConcreteObj 继承自 AbstractChild(存在1到n个具体实现类)
两个抽象类使用不同的Jackson多态鉴别器键:
- AbstractParent 通过
key1确定对应的 AbstractChild 子类型 - AbstractChild 通过
key2确定对应的 ConcreteObj 实现类
类代码实现
抽象父类
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "key1") @JsonSubTypes({ @JsonSubTypes.Type(value = AbstractChildA.class, name = "CHILD_A"), @JsonSubTypes.Type(value = AbstractChildB.class, name = "CHILD_B") }) public abstract class AbstractParent { private String key1; public AbstractParent() {} public AbstractParent(String key1) { this.key1 = key1; } }
抽象子类
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "key2") @JsonSubTypes({ @JsonSubTypes.Type(value = ConcreteObjX.class, name = "CONCRETE_X"), @JsonSubTypes.Type(value = ConcreteObjY.class, name = "CONCRETE_Y") }) public abstract class AbstractChild extends AbstractParent { private String key2; public AbstractChild() {} public AbstractChild(String key1, String key2) { super(key1); this.key2 = key2; } }
具体实现类
public class ConcreteObjX extends AbstractChild { private String someProperty; public ConcreteObjX() {} public ConcreteObjX(String key1, String key2, String someProperty) { super(key1, key2); this.someProperty = someProperty; } }
待反序列化的JSON
{ "key1": "CHILD_A", "key2": "CONCRETE_X", "someProperty": "test-value" }
问题现象
Jackson无法完成反序列化,抛出异常:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `AbstractChild` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have a custom deserializer, or contain additional type information.
已尝试的解决方法
- 确认两个抽象类都正确配置了
@JsonTypeInfo和@JsonSubTypes注解 - 检查ConcreteObjX已注册到AbstractChild的
@JsonSubTypes中 - 为所有抽象类和具体类添加了无参构造函数
- 尝试使用自定义反序列化器,但未成功
疑问
如何配置Jackson以正确反序列化这种每层抽象类使用独立鉴别器键的多层级多态结构?Jackson原生支持这种场景吗?还是必须使用自定义反序列化器?
解决方案
核心问题分析
Jackson默认处理多层多态时,会优先处理顶层父类的类型鉴别,当确定到AbstractChild类型后,不会自动触发子类的类型鉴别逻辑——顶层的@JsonTypeInfo配置会覆盖下层配置,导致Jackson尝试直接实例化抽象的AbstractChild类,从而抛出异常。
修复方案:添加visible = true属性
只需在顶层抽象类AbstractParent的@JsonTypeInfo注解中添加visible = true,让Jackson保留key1字段值的同时,继续识别子类的类型鉴别键key2。
修改后的AbstractParent代码:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "key1", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(value = AbstractChildA.class, name = "CHILD_A"), @JsonSubTypes.Type(value = AbstractChildB.class, name = "CHILD_B") }) public abstract class AbstractParent { private String key1; public AbstractParent() {} public AbstractParent(String key1) { this.key1 = key1; } }
原理说明
visible = true表示类型鉴别键(key1)会保留在JSON属性中,不会被Jackson在类型解析后移除- 当Jackson完成顶层类型解析(确定为AbstractChildA/B)后,会继续处理该子类上的
@JsonTypeInfo注解,读取key2的值确定最终的具体实现类(ConcreteObjX/Y)
额外注意事项
- 确保所有层级的
@JsonTypeInfo都使用As.EXISTING_PROPERTY模式,保证鉴别键是JSON中已存在的属性 - 具体实现类无需额外添加类型注解,只要正确注册到父类的
@JsonSubTypes中即可 - Jackson 2.12+版本完全原生支持该方案,无需自定义反序列化器
内容的提问来源于stack exchange,提问作者Aditya Gaddhyan
相关产品推荐
相关产品推荐

