[英]Polymorphic deserialization of JSON file with Jackson
Depending on the content of a JSON file, I want to deserialize it either to a superclass or subclass. 根据JSON文件的内容,我想将其反序列化为超类或子类。
It should be deserialized to the superclass if it looks like this: 如果看起来像这样,则应反序列化给超类:
{
"id":"123",
"title":"my title",
"body":"my body"
}
Or to the subclass if it looks like this: 或子类如下所示:
{
"id":"123",
"title":"my title",
"body":"my body",
"tags":["tag1", "tag2"]
}
So the only difference is the tags
array, which should be deserialized to a String array. 因此,唯一的区别是tags
数组,应将其反序列化为String数组。 But if I trigger the deserialization in Jersey (Dropwizard) via POST request, it returns {"code":400,"message":"Unable to process JSON"}
. 但是,如果我通过POST请求触发Jersey(Dropwizard)中的反序列化,它将返回{"code":400,"message":"Unable to process JSON"}
。
This is the superclass: 这是超类:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({ @JsonSubTypes.Type(name = "subdocument", value = SubDocument.class) })
public class SuperDocument {
private String id;
private String title;
private String body;
public SuperDocument() {
}
@JsonCreator
public SuperDocument(@JsonProperty("id") String id, @JsonProperty("title") String title, @JsonProperty("body") String body) {
this.id = id;
this.title = title;
this.body = body;
}
@JsonProperty("id")
public String getId() {
return id;
}
@JsonProperty("id")
public void setId(String id) {
this.id = id;
}
... the other getters and setters ...
}
This is the subclass: 这是子类:
@JsonTypeName("subdocument")
public class SubDocument extends SuperDocument {
private String[] tags;
public SubDocument() {
}
@JsonCreator
public SubDocument(@JsonProperty("id") String id, @JsonProperty("title") String title, @JsonProperty("body") String body, @JsonProperty("tags") String[] tags) {
super(id, title, body);
this.tags = tags;
}
@JsonProperty("tags")
public String[] getTags() {
return tags;
}
@JsonProperty("tags")
public void setTags(String[] tags) {
this.tags = tags;
}
}
Do you know what I am doing wrong? 你知道我在做什么错吗?
JsonTypeInfo
require a property that can identify your sub-class/super class. JsonTypeInfo
需要一个可以标识您的子类/超类的属性。 For eg: 例如:
{
"id":"123",
"title":"my title",
"body":"my body",
"type":"superdocument"
}
and 和
{
"id":"123",
"title":"my title",
"body":"my body",
"tags":["tag1", "tag2"],
"type":"subdocument"
}
Then modify SuperDocument annotations as shown below. 然后,如下所示修改SuperDocument批注。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,property="type")
@JsonSubTypes({ @JsonSubTypes.Type(name = "subdocument", value = SubDocument.class),@JsonSubTypes.Type(name = "superdocument", value = SuperDocument.class) })
public class SuperDocument {
}
If you don't want to intrduce an additional property "type", then you may have to write a custom type resolver and type deserializer as shown below. 如果您不想引入其他属性“ type”,则可能必须编写一个自定义类型解析器和类型反序列化器,如下所示。
public class DocumentTypeResolver extends StdTypeResolverBuilder {
@Override
public TypeDeserializer buildTypeDeserializer(
final DeserializationConfig config, final JavaType baseType, final Collection<NamedType> subtypes) {
return new DocumentDeserializer(baseType, null,
_typeProperty, _typeIdVisible, _defaultImpl);
}
}
Custom TypeDeserializer 自定义类型反序列化器
public static class DocumentDeserializer extends AsPropertyTypeDeserializer {
public DocumentDeserializer(final JavaType bt, final TypeIdResolver idRes, final String typePropertyName, final boolean typeIdVisible, final Class<?> defaultImpl) {
super(bt, idRes, typePropertyName, typeIdVisible, defaultImpl);
}
public DocumentDeserializer(final AsPropertyTypeDeserializer src, final BeanProperty property) {
super(src, property);
}
@Override
public TypeDeserializer forProperty(final BeanProperty prop) {
return (prop == _property) ? this : new DocumentDeserializer(this, prop);
}
@Override
public Object deserializeTypedFromObject(final JsonParser jp, final DeserializationContext ctxt) throws IOException {
JsonNode node = jp.readValueAsTree();
Class<?> subType =null;
JsonNode tags = node.get("tags");
if (tags == null) {
subType=SuperDocument.class;
} else {
subType=SubDocument.class;
}
JavaType type = SimpleType.construct(subType);
JsonParser jsonParser = new TreeTraversingParser(node, jp.getCodec());
if (jsonParser.getCurrentToken() == null) {
jsonParser.nextToken();
}
JsonDeserializer<Object> deser = ctxt.findContextualValueDeserializer(type, _property);
return deser.deserialize(jsonParser, ctxt);
}
}
Now annotate your SuperDocument
class as shown below 现在注释您的SuperDocument
类,如下所示
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonTypeResolver(DocumentTypeResolver.class)
public class SuperDocument {
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.