首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Jackson将WRAPPER_OBJECT键反序列化为属性

使用Jackson将WRAPPER_OBJECT键反序列化为属性
EN

Stack Overflow用户
提问于 2019-10-06 18:37:55
回答 1查看 1.7K关注 0票数 2

我试图将这个json数据反序列化为对象列表:

代码语言:javascript
复制
[{
  "a": {
    "commonField": 1,
    "aField": "AAA"
  }
}, {
  "b": {
    "commonField": 2,
    "bField": "BBB"
  }
}]

每个对象都可能是具有公共字段和唯一字段的几种类型之一。有关对象的确切形状的信息存储在json中,作为包装器对象中的键。

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

代码语言:javascript
复制
@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;
}

有了这个设计,杰克逊的工作几乎是完美的。它能够在反序列化过程中选择正确的子类型,并填充所有字段,包括公共字段和唯一字段。但是,type字段不会由Jackson更新,用于选择子类型的键值不会存储在任何地方。换句话说,数据被反序列化为以下结构:

代码语言:javascript
复制
[KeyBasedSubTypeA { type=null; commonField=1; aField=AAA },
 KeyBasedSubTypeB { type=null; commonField=2; bField=BBB }]

注意具有空值的type字段。因此,问题是-如何使杰克逊存储包装器的密钥,用于选择结果对象中的某个子类型?

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

代码语言:javascript
复制
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);
  }

}
EN

回答 1

Stack Overflow用户

发布于 2019-10-07 18:52:26

解决方案其实是非常接近,只是错过了一小步前进。@JsonTypeInfo(visible=true)要求将杰克逊处理类型信息作为正常属性。

代码语言:javascript
复制
@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;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58260217

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档