Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Jackson将包装器对象键反序列化为属性_Java_Json_Jackson - Fatal编程技术网

Java 使用Jackson将包装器对象键反序列化为属性

Java 使用Jackson将包装器对象键反序列化为属性,java,json,jackson,Java,Json,Jackson,我正在尝试将此json数据反序列化到对象列表中: [{ "a": { "commonField": 1, "aField": "AAA" } }, { "b": { "commonField": 2, "bField": "BBB" } }] 每个对象可以是具有公共字段和唯一字段的几种类型之一。关于对象的确切形状的信息存储在json中,作为包装器对象中的键 我为每个已知形状(一组唯一字段)创建了相应的类,扩展了包含所有公共字段的类。此外,我还向类

我正在尝试将此json数据反序列化到对象列表中:

[{
  "a": {
    "commonField": 1,
    "aField": "AAA"
  }
}, {
  "b": {
    "commonField": 2,
    "bField": "BBB"
  }
}]
每个对象可以是具有公共字段和唯一字段的几种类型之一。关于对象的确切形状的信息存储在json中,作为包装器对象中的键

我为每个已知形状(一组唯一字段)创建了相应的类,扩展了包含所有公共字段的类。此外,我还向类添加了Jackson注释,以支持多态反序列化。简化的结果类如下所示:

@JsonTypeInfo(use = Id.NAME, include = As.WRAPPER_OBJECT, property = "type")
@JsonSubTypes({
  @JsonSubTypes.Type(KeyBasedSubTypeA.class),
  @JsonSubTypes.Type(KeyBasedSubTypeB.class)
})
public abstract class KeyBasedSuperType {
  public String type;
  public int commonField;
}

@JsonTypeName("a")
public class KeyBasedSubTypeA extends KeyBasedSuperType {
  public String aField;
}

@JsonTypeName("b")
public class KeyBasedSubTypeB extends KeyBasedSuperType {
  public String bField;
}
在这种设置下,Jackson几乎可以完美地工作。它能够在反序列化期间选择正确的子类型,并填充所有字段,包括common和unique。但是,Jackson不会更新
类型
字段,用于选择子类型的键值不会存储在任何位置。换句话说,数据被反序列化为以下结构:

[KeyBasedSubTypeA { type=null; commonField=1; aField=AAA },
 KeyBasedSubTypeB { type=null; commonField=2; bField=BBB }]
注意
类型
字段具有空值。所以,问题是-如何让Jackson将用于选择子类型的包装器密钥存储在结果对象的某处?

下面是我对这个过程的JUnit测试

public class PolymorphicTest {
  private static ObjectMapper mapper;

  @BeforeClass
  public static void init() {
    mapper = new ObjectMapper();
  }

  @Test
  public void testKeyDenominator() throws IOException {
    TypeReference<List<KeyBasedSuperType>> dataShape =
        new TypeReference<List<KeyBasedSuperType>>() {};
    List<KeyBasedSuperType> result = mapper.readValue(
        PolymorphicTest.class.getResourceAsStream("polymorphic-key.json"), dataShape);
    assertEquals(2, result.size());
    assertEquals(KeyBasedSubTypeA.class, result.get(0).getClass());
    assertEquals(KeyBasedSubTypeB.class, result.get(1).getClass());
    assertEquals(1, result.get(0).commonField);
    assertEquals(2, result.get(1).commonField);
    assertEquals("a", result.get(0).type); // <---- this line fails
    assertEquals("b", result.get(1).type); // <---- this line fails
    assertEquals("AAA", ((KeyBasedSubTypeA) result.get(0)).aField);
    assertEquals("BBB", ((KeyBasedSubTypeB) result.get(1)).bField);
  }

}
公共类多态测试{
私有静态对象映射器映射器;
@课前
公共静态void init(){
映射器=新的ObjectMapper();
}
@试验
public void testKeyDenominator()引发IOException{
类型引用数据形状=
新的TypeReference(){};
列表结果=mapper.readValue(
PolymorphicTest.class.getResourceAsStream(“polymorphic key.json”),dataShape);
assertEquals(2,result.size());
assertEquals(KeyBasedSubTypeA.class,result.get(0.getClass());
assertEquals(KeyBasedSubTypeB.class,result.get(1.getClass());
assertEquals(1,result.get(0).commonField);
assertEquals(2,result.get(1),commonField);

assertEquals(“a”,result.get(0.type);//解决方案实际上非常接近,只是错过了一小步。使Jackson将类型信息作为普通属性处理需要
@JsonTypeInfo(visible=true)

@JsonTypeInfo(use = Id.NAME, include = As.WRAPPER_OBJECT, property = "type", visible = true)
@JsonSubTypes({
  @JsonSubTypes.Type(KeyBasedSubTypeA.class),
  @JsonSubTypes.Type(KeyBasedSubTypeB.class)
})
public abstract class KeyBasedSuperType {
  public String type;
  public int commonField;
}

type
字段由
Jackson
在内部处理,您的类中不应该有此属性。您可以创建
公共抽象字符串getType()
方法并在每个类中实现,因为您知道类型。您描述的行为是默认行为,但可以通过
@JsonTypeInfo
注释上的
visible=true
进行更改