这是我想出的一个解决方案,它扩展了Erik Gillespie的解决方案。它完全符合您的要求,并且对我有用。
使用 Jackson 2.9
@JsonDeserialize(using = CustomDeserializer.class)
public abstract class BaseClass {
private String commonProp;
}
// Important to override the base class' usage of CustomDeserializer which produces an infinite loop
@JsonDeserialize(using = JsonDeserializer.None.class)
public class ClassA extends BaseClass {
private String classAProp;
}
@JsonDeserialize(using = JsonDeserializer.None.class)
public class ClassB extends BaseClass {
private String classBProp;
}
public class CustomDeserializer extends StdDeserializer<BaseClass> {
protected CustomDeserializer() {
super(BaseClass.class);
}
@Override
public BaseClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
TreeNode node = p.readValueAsTree();
// Select the concrete class based on the existence of a property
if (node.get("classAProp") != null) {
return p.getCodec().treeToValue(node, ClassA.class);
}
return p.getCodec().treeToValue(node, ClassB.class);
}
}
// Example usage
String json = ...
ObjectMapper mapper = ...
BaseClass instance = mapper.readValue(json, BaseClass.class);
如果你想变得更花哨,你可以扩展以包括一个映射属性名称的属性名称,当存在时,该属性名称将映射到特定的类。本文介绍了这种方法。CustomDeserializer
Map<String, Class<?>>
更新
Jackson 2.12.0 从可用字段获取多态子类型演绎,这增加了 !@JsonTypeInfo(use = DEDUCTION)
AsDeductionTypeDeserializer 实现从字段中推断子类型的推断演绎。作为一个不打算合并的POC,tere需要大量的剪切粘贴代码等,但我认为功能性PR将是讨论我出于兴趣而写的东西的最佳基础。
它的工作原理是在注册时对每个子类型的整套可能字段进行指纹识别。在反序列化时,可用字段与这些指纹进行比较,直到只剩下一个候选项。它专门只查看直系子字段名称,因为现有机制涵盖了直系子级值,而更深层次的分析是一项更具强制性的ML任务,而不是Jackson职权范围的一部分。
顺便说一句,有一个(现已关闭的)Github问题在这里请求:https://github.com/FasterXML/jackson-databind/issues/1627