杰克逊基于类型反序列化

2022-09-02 14:26:45

假设我有以下格式的JSON:

{
    "type" : "Foo"
    "data" : {
        "object" : {
            "id" : "1"
            "fizz" : "bizz"
            ...
        },
        "metadata" : {
            ...
        },
        "owner" : {
            "name" : "John"
            ...
        }
    }
}

我试图避免自定义反序列化程序,并尝试将上述JSON(称为Trampr.java)反序列化为Java POJO。“type”字段指示“对象”反序列化,即。type = foo 表示使用 Foo.java反序列化“对象”字段。(如果类型 = Bar,请使用 Bar.java反序列化对象字段)。元数据/所有者将始终以相同的方式反序列化,为每个元数据/所有者使用一个简单的 Jackson 注释 Java 类。有没有办法使用注释来完成此操作?如果没有,如何使用自定义反序列化程序完成此操作?


答案 1

仅注释方法

或者,对于自定义反序列化程序方法,您可以为仅注释解决方案提供以下功能(类似于 Spunc 的答案中描述的解决方案,但用作外部属性):type

public abstract class AbstractData {

    private Owner owner;

    private Metadata metadata;

    // Getters and setters
}
public static final class FooData extends AbstractData {

    private Foo object;

    // Getters and setters
}
public static final class BarData extends AbstractData {

    private Bar object;

    // Getters and setters
}
public class Wrapper {

    private String type;

    @JsonTypeInfo(use = Id.NAME, property = "type", include = As.EXTERNAL_PROPERTY)
    @JsonSubTypes(value = { 
            @JsonSubTypes.Type(value = FooData.class, name = "Foo"),
            @JsonSubTypes.Type(value = BarData.class, name = "Bar") 
    })
    private AbstractData data;

    // Getters and setters
}

在此方法中,@JsonTypeInfo设置为用作外部属性,以确定映射属性的正确类。typedata

JSON 文档可以按如下方式反序列化:

ObjectMapper mapper = new ObjectMapper();
Wrapper wrapper = mapper.readValue(json, Wrapper.class);  

答案 2

自定义反序列化程序方法

可以使用检查属性的自定义反序列化程序将属性分析为最合适的类。typeobject

首先定义一个将由 和 类实现的接口:FooBar

public interface Model {

}
public class Foo implements Model {

    // Fields, getters and setters
}
public class Bar implements Model {

    // Fields, getters and setters
}

然后定义您的和类:WrapperData

public class Wrapper {

    private String type;

    private Data data;

    // Getters and setters
}
public class Data {

    @JsonDeserialize(using = ModelDeserializer.class)
    private Model object;

    private Metadata metadata;

    private Owner owner;

    // Getters and setters
}

该字段使用@JsonDeserialize进行批注,指示将用于该属性的反序列化程序。objectobject

反序列化程序定义如下:

public class ModelDeserializer extends JsonDeserializer<Model> {

    @Override
    public Model deserialize(JsonParser jp, DeserializationContext ctxt)
        throws IOException, JsonMappingException {

        // Get reference to ObjectCodec
        ObjectCodec codec = jp.getCodec();

        // Parse "object" node into Jackson's tree model
        JsonNode node = codec.readTree(jp);

        // Get value of the "type" property
        String type = ((Wrapper) jp.getParsingContext().getParent()
            .getCurrentValue()).getType();

        // Check the "type" property and map "object" to the suitable class
        switch (type) {

            case "Foo":
                return codec.treeToValue(node, Foo.class);

            case "Bar":
                return codec.treeToValue(node, Bar.class);

            default:
                throw new JsonMappingException(jp, 
                    "Invalid value for the \"type\" property");
        }
    }
}

JSON 文档可以按如下方式反序列化:

ObjectMapper mapper = new ObjectMapper();
Wrapper wrapper = mapper.readValue(json, Wrapper.class);  

或者,对于此自定义反序列化程序,请考虑仅使用批注的方法