Java 使用Jackson将包装器对象键反序列化为属性
我正在尝试将此json数据反序列化到对象列表中:Java 使用Jackson将包装器对象键反序列化为属性,java,json,jackson,Java,Json,Jackson,我正在尝试将此json数据反序列化到对象列表中: [{ "a": { "commonField": 1, "aField": "AAA" } }, { "b": { "commonField": 2, "bField": "BBB" } }] 每个对象可以是具有公共字段和唯一字段的几种类型之一。关于对象的确切形状的信息存储在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
进行更改