驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
Jaskson处理复杂的泛型对象-非最优方案
/    

Jaskson处理复杂的泛型对象-非最优方案

开篇

Jackson是一个在Java体系中被广泛使用的Json序列化和反序列化类库,它提供了丰富的API给开发者使用。

今天记录下最近利用Jackson处理复杂的泛型对象的心得,其核心就是利用TypeFactory.constructParametricType()方法,从内到外依此构造Type。

  • 范例1:List<Map<String, Person>>
  • 范例2:Map<String, List<Person>>

范例1: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>>

需要注意的是,在构造的时候需要从内到外进行构造:

  1. 先构造Map<String,Person>得到innerType

  2. 再构造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。

范例2: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());

结语

核心思路:从内到外构造类型,一步一步来!

骐骥一跃,不能十步。驽马十驾,功在不舍。