我试图将这个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;
}有了这个设计,杰克逊的工作几乎是完美的。它能够在反序列化过程中选择正确的子类型,并填充所有字段,包括公共字段和唯一字段。但是,type字段不会由Jackson更新,用于选择子类型的键值不会存储在任何地方。换句话说,数据被反序列化为以下结构:
[KeyBasedSubTypeA { type=null; commonField=1; aField=AAA },
KeyBasedSubTypeB { type=null; commonField=2; bField=BBB }]注意具有空值的type字段。因此,问题是-如何使杰克逊存储包装器的密钥,用于选择结果对象中的某个子类型?
下面是我对这个过程的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);
}
}发布于 2019-10-07 18:52:26
解决方案其实是非常接近,只是错过了一小步前进。@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;
}https://stackoverflow.com/questions/58260217
复制相似问题