TL; DR - 包含一个成员的包装类,该成员是一个用@JsonTypeInfo
注释的抽象类的列表。
我有一个包装类和一个带有根抽象类的类层次结构,一个子抽象类和一个具体的孙子。
public static class RootClassWrapper {
public static final String JSON_KEY_ROOT_CLASS_LIST =
"root_class_list";
@JsonProperty(JSON_KEY_ROOT_CLASS_LIST)
private final List<RootClass> rootClassList;
@JsonCreator
public RootClassWrapper(
@JsonProperty(JSON_KEY_ROOT_CLASS_LIST)
final List<RootClass> rootClassList) {
this.rootClassList = rootClassList;
}
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = RootClass.JSON_KEY_ROOT_CLASS_TYPE)
@JsonSubTypes({
@JsonSubTypes.Type(
value = GrandchildClass.class,
name = GrandchildClass.CHILD_CLASS_TYPE) })
public static abstract class RootClass {
public static final String JSON_KEY_ROOT_CLASS_TYPE = "root_class_type";
public static final String JSON_KEY_ID = "id";
@JsonProperty(JSON_KEY_ID)
private final String id;
@JsonCreator
public RootClass(
@JsonProperty(JSON_KEY_ID) final String id) {
this.id = id;
}
}
public static abstract class ChildClass extends RootClass {
@JsonCreator
public ChildClass(
@JsonProperty(JSON_KEY_ID) final String id) {
super(id);
}
}
public static class GrandchildClass extends ChildClass {
public static final String CHILD_CLASS_TYPE = "grandchild";
@JsonCreator
public GrandchildClass(
@JsonProperty(JSON_KEY_ID) final String id) {
super(id);
}
}
尝试使用此层次结构:
ByteArrayOutputStream out = new ByteArrayOutputStream();
GrandchildClass grandchildClass = new GrandchildClass("grandchildId");
List<RootClass> rootClassList = new ArrayList<RootClass>(1);
rootClassList.add(grandchildClass);
RootClassWrapper wrapper = new RootClassWrapper(rootClassList);
mapper.writeValue(out, wrapper);
System.out.println(out.toString());
RootClassWrapper rootClassWrapper =
mapper.readValue(out.toString(), RootClassWrapper.class);
mapper.writeValue(System.out, rootClassWrapper);
对象可以序列化,System.out.println(out.toString());
可以观察到:
{"root_class_list":[{"root_class_type":"grandchild","id":"grandchildId"}]}
但是同一输出的反序列化会导致以下错误:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Could not find creator property with name 'id' (in class test.Test$RootClass)
at [Source: java.io.StringReader@13de68e2; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:584)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:551)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:267)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:168)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:405)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:354)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:267)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:247)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:146)
at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:305)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:151)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:23)
at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:309)
at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.construct(PropertyBasedCreator.java:96)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:414)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:298)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:247)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:146)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:2990)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2884)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
at test.Test.main(Test.java:130)
答案 0 :(得分:3)
还有一个错误,但这可行
为RootClass
创建一个私有的默认构造函数,用@JsonCreator
标记它,并从现有构造函数中删除注释似乎有效。中间抽象类的@JsonCreator
注释是无关紧要的。
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = RootClass.JSON_KEY_ROOT_CLASS_TYPE)
@JsonSubTypes({
@JsonSubTypes.Type(
value = GrandchildClass.class,
name = GrandchildClass.CHILD_CLASS_TYPE) })
public static abstract class RootClass {
public static final String JSON_KEY_ROOT_CLASS_TYPE = "root_class_type";
public static final String JSON_KEY_ID = "id";
@JsonProperty(JSON_KEY_ID)
private final String id;
@JsonCreator
private RootClass() {
id = null;
}
public RootClass(final String id) {
this.id = id;
}
}
public static abstract class ChildClass extends RootClass {
/**
* The annotations here don't matter.
*/
@JsonCreator
public ChildClass(@JsonProperty(JSON_KEY_ID) final String id) {
super(id);
}
}
public static class GrandchildClass extends ChildClass {
public static final String CHILD_CLASS_TYPE = "grandchild";
@JsonCreator
public GrandchildClass(@JsonProperty(JSON_KEY_ID) final String id) {
super(id);
}
}