JSON反序列化中的泛型问题及解决方法
1、问题
Java的泛型是编译期擦除,因此反序列化无法直接指定泛型类型:
List<User> list = JsonbBuilder.create().fromJson(json, List<User>.class);
编译不通过,改为List.class又达不到预期效果。
2、解决办法
jackson的做法:
List<User> list = JsonbBuilder.create().fromJson(json, new TypeReference<List<User>>(){});
注:Java 泛型擦除机制下,只有匿名子类能保留运行时泛型信息,预定义子类无法实现这一点。所以上面TypeReference后面的一对大括号不能省。
new TypeReference<>(){} 实际上是创建了一个TypeReference的 匿名子类。匿名子类的类定义会 保留父类的泛型参数信息(通过 getGenericSuperclass() 可获取)。
因此,如果提前预定义一个TypeReference的子类ConcreteType,再new ConcreteType<List
以上机制,可以了解一下Java泛型的规范:
具体类的泛型参数在运行时不可见,只有匿名类或反射生成的类型能保留。
johnzon的做法:
List<User> list = JsonbBuilder.create().fromJson(json, new JohnzonCollectionType<List<User>>(){});
genson的做法:
List<User> list = JsonbBuilder.create().fromJson(json, new GenericType<List<User>>(){});
或者使用构造方法传入类型类和泛型类
List<User> list = JsonbBuilder.create().fromJson(json, new JohnzonParameterizedType(List.class, User.class));
注:User.class后面还可以接更多的泛型参数
总结
巧妙之处,Java虽然是泛型擦除,但子类可以拿到父类上的泛型类型。
所以TypeReference、JohnzonCollectionType、GenericType,无一例外都是抽象类,后面接了对大括号,表示是创建了该抽象类的匿名子类的实例,再由实例在运行时获取父类的泛型类型。

浙公网安备 33010602011771号