使用Jackson对JSON文件进行多态反序列化

时间:2017-03-25 18:45:46

标签: java json jackson polymorphism deserialization

根据JSON文件的内容,我想将其反序列化为超类或子类。

如果看起来像这样,它应该被反序列化到超类:

{
   "id":"123",
   "title":"my title",
   "body":"my body"
}

如果它看起来像这样的子类:

{
   "id":"123",
   "title":"my title",
   "body":"my body",
   "tags":["tag1", "tag2"]
}

所以唯一的区别是tags数组,应该反序列化为String数组。 但是如果我通过POST请求在Jersey(Dropwizard)中触发反序列化,它将返回{"code":400,"message":"Unable to process JSON"}

这是超类:

@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 ...
}

这是子类:

@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;
}
}

你知道我做错了吗?

1 个答案:

答案 0 :(得分:1)

JsonTypeInfo需要一个可以识别您的子类/超类的属性。例如:

{
   "id":"123",
   "title":"my title",
   "body":"my body",
   "type":"superdocument"
}

{
   "id":"123",
   "title":"my title",
   "body":"my body",
   "tags":["tag1", "tag2"],
   "type":"subdocument"
}

然后修改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 {

}

如果您不想引用其他属性"键入",则可能必须编写自定义类型解析程序并键入反序列化程序,如下所示。

    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);

    }

}

现在注释您的SuperDocument课程,如下所示

@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonTypeResolver(DocumentTypeResolver.class)
public class SuperDocument {

}