Jackson是一个在Java体系中被广泛使用的Json序列化和反序列化类库,它提供了丰富的API给开发者使用。
今天记录下最近利用Jackson处理复杂的泛型对象的心得,其核心就是利用TypeFactory.constructParametricType()
方法,从内到外依此构造Type。
List<Map<String, Person>>
Map<String, List<Person>>
List<Map<String, Person>>
假设我有一个对象List<Map<String, Person>>
,我先构造对象然后转为字符串。
//init
List<Map<String, Person>> result = new ArrayList<>();
Map<String, Person> map = new HashMap<>();
map.put("lcf", new Person("lcf"));
Map<String, Person> map2 = new HashMap<>();
map2.put("hh", new Person("hh"));
result.add(map);
result.add(map2);
//toStr
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(result);
然后将其反序列化:
//toObj JsonMappingException,json转化异常
Map map1 = mapper.readValue(s, Map.class);
直接这样转换是会报错的!
需要利用 TypeFactory.constructParametricType()
进行JavaType
的类型构造:List<Map<String, Person>>
需要注意的是,在构造的时候需要从内到外进行构造:
先构造Map<String,Person>
得到innerType
再构造List<innerType>
代码如下所示:
//先构造Map<String,Person>得到innerType,第一个参数为外层对象HashMap,第二个参数为String,第三个参数为Person
JavaType innerType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, Person.class);
//再构造List<innerType>
JavaType resultType = mapper.getTypeFactory().constructParametricType(ArrayList.class, innerType);
//反序列化
List<Map<String, Person>> result2 = mapper.readValue(s, resultType);
建议用实际的子类型来代替:比如Map 精确为 HashMap,List精确为实际的ArrayList。
Map<String, List<Person>>
//构造 Map<String, List<Person>>
//1.先构造右边部分
JavaType rightType = mapper.getTypeFactory().constructParametricType(ArrayList.class, Person.class);
//2. 再构造全局
JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, rightType.getRawClass());
Map<String, List<Person>> o = mapper.readValue(str, javaType);
这里有一个小知识点,注意的是参数类型要匹配:constructParametricType
方法有如下2种声明需要注意:
public JavaType constructParametricType(Class<?> parametrized, Class<?>... parameterClasses)
public JavaType constructParametricType(Class<?> rawType, JavaType... parameterTypes)
方法中后面的可变形参参数必须一致。
可以查看返利2的 再构造全局,我本来是希望:
JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, rightType);
但是IDE提示参数不匹配,认真一查看确实是:一个是Class,一个是JavaType。
所以通过直接getRawClass
解决该问题:
//构造 Map<String, List<Person>>
JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, rightType.getRawClass());
核心思路:从内到外构造类型,一步一步来!