Java 动态类型的Jackson多态反序列化
我有一个包含一些强类型字段和一些松散类型字段的数据结构。其中一些字段是可以是任何深度嵌套的集合 示例JSONJava 动态类型的Jackson多态反序列化,java,json,jackson,Java,Json,Jackson,我有一个包含一些强类型字段和一些松散类型字段的数据结构。其中一些字段是可以是任何深度嵌套的集合 示例JSON { "prop": "Hello", //strongly-typed "child1": { "anInt": -1 }, "map": { // here magic begins "JustString": "JustValue", // we may store any Obje
{
"prop": "Hello", //strongly-typed
"child1": {
"anInt": -1
},
"map": { // here magic begins
"JustString": "JustValue", // we may store any Object in this map
"Item_With_Type": {
"@type": "MyMap", // some of them tell their type and we need to rely on it
"Custom": "Value"
},
"List_With_All_Child1": {
"@type": "MyMap[]", // lists define the type of all values in it in this way
"@values": [
{
"Key": "Value", // MyMap is a Map
"Child1": { // of <? extends Object>
"anInt": 2
}
},
{
"Key": "Value"
}
]
}
}
}
{
“prop”:“Hello”,//强类型
“儿童1”:{
“anInt”:-1
},
“地图”:{//魔法开始了
“JustString”:“JustValue”,//我们可以在此映射中存储任何对象
“带有类型的项目”:{
“@type”:“MyMap”//有些人告诉我们他们的类型,我们需要依赖它
“自定义”:“值”
},
“列出所有子女的子女1”:{
“@type”:“MyMap[]”,//列表以这种方式定义其中所有值的类型
“@values”:[
{
“键”:“值”//MyMap是一个映射
“Child1”:{//map;
}
公共静态类Child1{
私人内部信息;
}
公共静态类MyMap扩展HashMap实现Map{
}
(省略访问器)
基本上,我需要一种数据绑定器,Jackson每次尝试为任何字段保存上下文解析类型时都会询问该类型,如果该数据绑定器没有找到任何特定于应用程序的内容,Jackson应该返回默认类型解析
有什么办法可以做到这一点吗?和杰克逊一起玩了一段时间后,我想到了以下解决方案。对我来说效果很好 首先,我们让一切都是多态的
@JsonTypeResolver(MyTypeResolver.class)
@JsonTypeIdResolver(MyTypeIdResolver.class)
@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.PROPERTY, property = "@type")
public interface ObjectMixin {
}
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.addMixIn(Object.class, ObjectMixin.class);
我们创建的自定义类型解析器只处理java.lang.Object
的类型序列化/反序列化
public class MyTypeResolver extends StdTypeResolverBuilder {
@Override
public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
return useForType(baseType) ? super.buildTypeSerializer(config, baseType, subtypes) : null;
}
@Override
public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
return useForType(baseType) ? super.buildTypeDeserializer(config, baseType, subtypes) : null;
}
public boolean useForType(JavaType t) {
return t.isJavaLangObject();
}
}
可以跳过子类的创建,但是类型信息会添加到每个元素中。java.lang.*
类当然没有类型信息
模型包括:
public class Parent {
private String prop;
private Child1 child1;
private MyMap map;
}
public class Child1 {
private int anInt;
}
测试代码:
@Test
public void shouldDoTheTrick() throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.addMixIn(Object.class, ObjectMixin.class);
Parent parent = new Parent("Hello", new Child1(-1), new MyMap() {{
put("JustString", "JustValue");
put("List_With_All_MyMaps", new ListWrapper.MyMapListWrapper(new ArrayList<MyMap>() {{
add(new MyMap() {{
put("Key", "Value");
put("object", new Child1(2));
}});
add(new MyMap() {{
put("Key", "Value");
}});
}}));
put("List_With_All_Child1", new ListWrapper.Child1ListWrapper(new ArrayList<Child1>() {{
add(new Child1(41));
add(new Child1(42));
}}));
}});
String valueAsString = mapper.writeValueAsString(parent);
Parent deser = mapper.readValue(valueAsString, Parent.class);
assertEquals(parent, deser);
}
UPD:真正的实现示例请不要在堆栈溢出上的问题中发布代码链接。试试
ObjectMapper
它可能适合您。
public class ListWrapper<T> {
@JsonProperty("@values")
private List<T> values;
public static class MyMapListWrapper extends ListWrapper<MyMap> {
}
public static class Child1ListWrapper extends ListWrapper<Child1> {
}
}
public class Parent {
private String prop;
private Child1 child1;
private MyMap map;
}
public class Child1 {
private int anInt;
}
@Test
public void shouldDoTheTrick() throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.addMixIn(Object.class, ObjectMixin.class);
Parent parent = new Parent("Hello", new Child1(-1), new MyMap() {{
put("JustString", "JustValue");
put("List_With_All_MyMaps", new ListWrapper.MyMapListWrapper(new ArrayList<MyMap>() {{
add(new MyMap() {{
put("Key", "Value");
put("object", new Child1(2));
}});
add(new MyMap() {{
put("Key", "Value");
}});
}}));
put("List_With_All_Child1", new ListWrapper.Child1ListWrapper(new ArrayList<Child1>() {{
add(new Child1(41));
add(new Child1(42));
}}));
}});
String valueAsString = mapper.writeValueAsString(parent);
Parent deser = mapper.readValue(valueAsString, Parent.class);
assertEquals(parent, deser);
}
{
"prop" : "Hello",
"child1" : {
"anInt" : -1
},
"map" : {
"JustString" : "JustValue",
"List_With_All_MyMaps" : {
"@type" : "MyMap[]",
"@values" : [ {
"Key" : "Value",
"object" : {
"@type" : "Child1",
"anInt" : 2
}
}, {
"Key" : "Value"
} ]
},
"List_With_All_Child1" : {
"@type" : "Child1[]",
"@values" : [ {
"anInt" : 41
}, {
"anInt" : 42
} ]
}
}
}