Jackson根据json在同一个class映射不同的属性

Jackson map different attributes based on json in the same class

我有一个 class Response,它有一个属性 data

一个json文件被映射到这个对象。 data 属性可以是 json 上的 TaskDataSubmitData 类型。

如果 json 具有 TaskData 类型的对象,对象映射器必须映射到 TaskData class 或者应该映射到 `SubmitData' class .

您需要按如下方式输入 Response class:public class Response<T>.

然后,在反序列化输入时,向 jackson 提供一个 TypeReference 以指示所需的类型。

看这个例子:

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TestJacksonTyping {

    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        Response<TaskData> taskResponse = new Response<TaskData>();
        TaskData taskData = new TaskData();
        taskData.setTaskTitle("Some title");
        taskResponse.setData(taskData);
        Response<SubmitData> submitResponse = new Response<SubmitData>();
        SubmitData submitData = new SubmitData();
        submitData.setSubmitValue(256);
        submitResponse.setData(submitData);
        StringWriter sw = new StringWriter();
        mapper.writeValue(sw, taskResponse);
        String taskResponseJson = sw.toString();
        mapper.writeValue(sw = new StringWriter(), submitResponse);
        String submitResponseJson = sw.toString();
        Response<TaskData> deserializedTaskResponse = mapper.reader(new TypeReference<Response<TaskData>>() {
        }).readValue(new StringReader(taskResponseJson));
        Response<SubmitData> deserializedSubmitResponse = mapper.reader(new TypeReference<Response<SubmitData>>() {
        }).readValue(new StringReader(submitResponseJson));
        System.out.println(deserializedTaskResponse.getData().getTaskTitle());
        System.out.println(deserializedSubmitResponse.getData().getSubmitValue());

    }

    public static class Response<T> {
        private T data;

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }

    }

    public static class TaskData {
        private String taskTitle;

        public String getTaskTitle() {
            return taskTitle;
        }

        public void setTaskTitle(String taskTitle) {
            this.taskTitle = taskTitle;
        }
    }

    public static class SubmitData {
        private int submitValue;

        public int getSubmitValue() {
            return submitValue;
        }

        public void setSubmitValue(int submitValue) {
            this.submitValue = submitValue;
        }
    }

}

除了 Guillaume Polet 的回答,如果您可以修改 JSON 模式,这也可以通过注释使用 Jackson 的 Polymorphic (de)serialization 来更顺利地完成:

@JsonTypeInfo(use=JsonTypeInfo.Id.Class, include=JsonTypeInfo.As.PROPERTY, property="@class")
class Data {}

class TaskData extends Data {}
class SubmitData extends Data {}

这将写出完整的 Java class 名称作为附加 @class 属性。然而,json 需要在输入中包含 @class 属性。

代替JsonTypeInfo.Id.Class也可以执行显式命名

@JsonTypeInfo(use=JsonTypeInfo.Id.Class, include=JsonTypeInfo.As.PROPERTY, property="@dataType")
@JsonSubTypes({
    JsonSubTypes.Type(value=TaskData.class, name="task"),
    JsonSubTypes.Type(value=SubmitData.class, name="submit")
})
class Data {}

@JsonTypeName("task")
class TaskData extends Data {}
@JsonTypeName("submit")
class SubmitData extends Data {}

这将产生一个额外的合成字段 @dataType,它需要出现在输入中。

如果您无法在输入中明确显示类型 JSON,您将需要坚持使用手动方法。