杰克逊-在运行时解析相同密钥下的不同模型 [英] Jackson - parse different model under same key at runtime

查看:48
本文介绍了杰克逊-在运行时解析相同密钥下的不同模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从服务器收到一个特定的json响应,其中在一个键下,内容也将属于不同的模型,同时在该键下仅存在一个模型数据.

I have a specific json response from server, where under a key the content would be of different models also at a time only one of the model data would be present under the key.

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

While parsing the response into POJO how can I specify object type at runtime based on other field of contentType on same model.

以下是用于更好地了解场景的代码.

Following is the code for better understanding of scenario.

此处content_type为A类型,因此在"content"键下将存在类型为TypeA的对象的模型

Here content_type is type A and so under "content" key there would be model for object of class TypeA

"scheduled_content": {

  "some_field": "value",
  "content_type": "typeA",
  "content" : {
          "some_field" : "value"
          "more_feilds" : "value"
   }
 }

此处content_type为B型,因此在"content"键下将存在类型为TypeB的对象的模型

Here content_type is type B and so under "content" key there would be model for object of class TypeB

"scheduled_content": {

  "some_field": "value",
  "content_type": "typeB",
  "content" : {
          "some_field_b" : "value"
          "more_fields_for_b" : "value"
   }
 }

如何编写POJO类来解析此类json响应? 类型类是完全不同的模型,它们没有任何共同之处.

How can I write POJO classes to parse such json response? The type classes are completely different models they don't have any field in common.

推荐答案

我相信您正在寻找的东西用杰克逊JSON术语称为通过属性名称进行多态反序列化.

I believe that what you are looking for is called, in Jackson JSON terms, polymorphic deserialization by property name.

这是我使用杰克逊2.1.4的方法:

Here is how I do it with Jackson 2.1.4:

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

First create an abstract class ScheduledContent with common members and an abstract method that would operate on the content. Use the JsonTypeInfo annotation to mark the JSON property that would resolve the specific implementation and the JsonSubTypes annotation to register the subtypes by the values of the property previously specified:

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上完成子类型的注册.

The subtypes registration can also be done on the ObjectMapper as you will see later.

然后为ScheduledAContent类添加特定的实现:

Then add the specific implementation for the ScheduledAContent class:

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

其中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;
    }
}

以及ScheduledBContent类:

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

还有一个简单的Test类:

And a simple Test class:

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

这篇关于杰克逊-在运行时解析相同密钥下的不同模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆