Java Jackson-在运行时在同一密钥下解析不同的模型

Java Jackson-在运行时在同一密钥下解析不同的模型,java,json,jackson,Java,Json,Jackson,我有一个来自服务器的特定json响应,其中在一个键下,内容将是不同的模型,而且在同一时间,只有一个模型数据将出现在该键下 在将响应解析为POJO时,如何根据同一模型上contentType的其他字段在运行时指定对象类型 以下是更好地理解场景的代码 这里的内容类型是类型A,因此在“content”键下,会有类型A类对象的模型 "scheduled_content": { "some_field": "value", "content_type": "typeA", "content"

我有一个来自服务器的特定json响应,其中在一个键下,内容将是不同的模型,而且在同一时间,只有一个模型数据将出现在该键下

在将响应解析为POJO时,如何根据同一模型上contentType的其他字段在运行时指定对象类型

以下是更好地理解场景的代码

这里的内容类型是类型A,因此在
“content”
键下,会有类型A类对象的模型

"scheduled_content": {

  "some_field": "value",
  "content_type": "typeA",
  "content" : {
          "some_field" : "value"
          "more_feilds" : "value"
   }
 }
这里的内容类型是类型B,因此在
“content”
键下,会有类型B类对象的模型

"scheduled_content": {

  "some_field": "value",
  "content_type": "typeB",
  "content" : {
          "some_field_b" : "value"
          "more_fields_for_b" : "value"
   }
 }
如何编写POJO类来解析这样的json响应?
类型类是完全不同的模型,它们没有任何共同的字段。

在setter方法中使用@JsonSetter可能会有所帮助。但在这种情况下,您需要为“内容”中的每种类型的字段创建setter方法


在setter方法中使用@JsonSetter可能会有所帮助。但在这种情况下,您需要为“内容”中的每种类型的字段创建setter方法


我相信您正在寻找的东西,用Jackson JSON术语来说,就是按属性名进行的多态反序列化

以下是我如何使用Jackson 2.1.4:

首先创建一个抽象类
ScheduledContent
,其中包含公共成员和一个对内容进行操作的抽象方法。使用
JsonTypeInfo
注释标记将解析特定实现的JSON属性,并使用
JsonSubTypes
注释通过先前指定的属性值注册子类型:

import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "content_type")
@JsonSubTypes({
  @JsonSubTypes.Type(name = "typeA", value = ScheduledAContent.class),
  @JsonSubTypes.Type(name = "typeB", value = ScheduledBContent.class)
})
public abstract class ScheduledContent {
  private String someField;

  @JsonSetter("some_field")
  public void setSomeField(String someField) {
    this.someField = someField;
  }

  public abstract void doSomethingWithContent();
}
子类型注册也可以在
ObjectMapper
上完成,您将在后面看到

然后为
scheduledcontent
类添加特定实现:

public class ScheduledAContent extends ScheduledContent {
    private TypeAContent content;

    public void setContent(TypeAContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
public class ScheduledBContent extends ScheduledContent {
    private TypeBContent content;

    public void setContent(TypeBContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
TypeAContent
为:

import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeAContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeBContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field_b")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field_b")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
对于
ScheduledBContent
类:

public class ScheduledAContent extends ScheduledContent {
    private TypeAContent content;

    public void setContent(TypeAContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
public class ScheduledBContent extends ScheduledContent {
    private TypeBContent content;

    public void setContent(TypeBContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
TypeBContent
为:

import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeAContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeBContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field_b")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field_b")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
和一个简单的测试类:

import java.io.IOException;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.NamedType;

public class Test {
    public static void main(String[] args) {
        String jsonA = "{" +
                "\"some_field\": \"main_some_field1\"," +
                "\"content_type\": \"typeA\"," +
                "\"content\" : {" +
                "    \"some_field\" : \"content_some_field\"," +
                "    \"another_field\" : \"content_another_field\"" +
                "}}";

        String jsonB = "{" +
                "\"some_field\": \"main_some_field2\"," +
                "\"content_type\": \"typeB\"," +
                "\"content\" : {" +
                "    \"some_field_b\" : \"content_some_field_b\"," +
                "    \"another_field_b\" : \"content_another_field_b\"" +
                "}}";


        ObjectMapper mapper = new ObjectMapper();

        /*
         * This is another way to register the subTypes if you want to do it dynamically without the use of the
         * JsonSubTypes annotation in the ScheduledContent class
         */
//        mapper.registerSubtypes(new NamedType(ScheduledAContent.class, "typeA"));
//        mapper.registerSubtypes(new NamedType(ScheduledBContent.class, "typeB"));

        try {
            ScheduledContent scheduledAContent = mapper.readValue(jsonA, ScheduledContent.class);
            scheduledAContent.doSomethingWithContent();

            ScheduledContent scheduledBContent = mapper.readValue(jsonB, ScheduledContent.class);
            scheduledBContent.doSomethingWithContent();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
这将产生输出:

someField: content_some_field
anotherField: content_another_field
someField: content_some_field_b
anotherField: content_another_field_b

我相信您正在寻找的东西,用Jackson JSON术语来说,就是按属性名进行的多态反序列化

以下是我如何使用Jackson 2.1.4:

首先创建一个抽象类
ScheduledContent
,其中包含公共成员和一个对内容进行操作的抽象方法。使用
JsonTypeInfo
注释标记将解析特定实现的JSON属性,并使用
JsonSubTypes
注释通过先前指定的属性值注册子类型:

import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "content_type")
@JsonSubTypes({
  @JsonSubTypes.Type(name = "typeA", value = ScheduledAContent.class),
  @JsonSubTypes.Type(name = "typeB", value = ScheduledBContent.class)
})
public abstract class ScheduledContent {
  private String someField;

  @JsonSetter("some_field")
  public void setSomeField(String someField) {
    this.someField = someField;
  }

  public abstract void doSomethingWithContent();
}
子类型注册也可以在
ObjectMapper
上完成,您将在后面看到

然后为
scheduledcontent
类添加特定实现:

public class ScheduledAContent extends ScheduledContent {
    private TypeAContent content;

    public void setContent(TypeAContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
public class ScheduledBContent extends ScheduledContent {
    private TypeBContent content;

    public void setContent(TypeBContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
TypeAContent
为:

import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeAContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeBContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field_b")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field_b")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
对于
ScheduledBContent
类:

public class ScheduledAContent extends ScheduledContent {
    private TypeAContent content;

    public void setContent(TypeAContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
public class ScheduledBContent extends ScheduledContent {
    private TypeBContent content;

    public void setContent(TypeBContent content) {
        this.content = content;
    }

    @Override
    public void doSomethingWithContent() {
        System.out.println("someField: " + content.getSomeField());
        System.out.println("anotherField: " + content.getAnotherField());
    }
}
TypeBContent
为:

import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeAContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
import com.fasterxml.jackson.annotation.JsonSetter;

public class TypeBContent {
    private String someField;
    private String anotherField;

    @JsonSetter("some_field_b")
    public void setSomeField(String someField) {
        this.someField = someField;
    }

    public String getSomeField() {
        return someField;
    }

    @JsonSetter("another_field_b")
    public void setAnotherField(String anotherField) {
        this.anotherField = anotherField;
    }

    public String getAnotherField() {
        return anotherField;
    }
}
和一个简单的测试类:

import java.io.IOException;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.NamedType;

public class Test {
    public static void main(String[] args) {
        String jsonA = "{" +
                "\"some_field\": \"main_some_field1\"," +
                "\"content_type\": \"typeA\"," +
                "\"content\" : {" +
                "    \"some_field\" : \"content_some_field\"," +
                "    \"another_field\" : \"content_another_field\"" +
                "}}";

        String jsonB = "{" +
                "\"some_field\": \"main_some_field2\"," +
                "\"content_type\": \"typeB\"," +
                "\"content\" : {" +
                "    \"some_field_b\" : \"content_some_field_b\"," +
                "    \"another_field_b\" : \"content_another_field_b\"" +
                "}}";


        ObjectMapper mapper = new ObjectMapper();

        /*
         * This is another way to register the subTypes if you want to do it dynamically without the use of the
         * JsonSubTypes annotation in the ScheduledContent class
         */
//        mapper.registerSubtypes(new NamedType(ScheduledAContent.class, "typeA"));
//        mapper.registerSubtypes(new NamedType(ScheduledBContent.class, "typeB"));

        try {
            ScheduledContent scheduledAContent = mapper.readValue(jsonA, ScheduledContent.class);
            scheduledAContent.doSomethingWithContent();

            ScheduledContent scheduledBContent = mapper.readValue(jsonB, ScheduledContent.class);
            scheduledBContent.doSomethingWithContent();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
这将产生输出:

someField: content_some_field
anotherField: content_another_field
someField: content_some_field_b
anotherField: content_another_field_b