解决使用FastJson反序列化泛型类时,内部嵌套类型无法正确识别的问题
在开发中经常会遇到序列化和反序列化的问题,比较常用的是将对象序列化成json信息存储。
对于json信息的操作,我个人偏向于使用FastJson,这是一款java环境的json处理工具,由阿里爸爸开发。
项目地址:https://github.com/alibaba/fastjson
在开发中经常会遇到序列化和反序列化的问题,比较常用的是将对象序列化成json信息存储。
对于json信息的操作,我个人偏向于使用FastJson,这是一款java环境的json处理工具,由阿里爸爸开发。
项目地址:https://github.com/alibaba/fastjson
问题描述
泛型类A中组合一泛型类对象,使用FastJson的<T> T parseObject(String text, Class<T> clazz, @Nullable Feature... features)
方法对序列化后A对象的值进行反序列化时,无法正确识别类型擦除前嵌套类的真实类型,从而导致反序列化后的嵌套类类型为Object。
1 | class A<T> { |
搞一下
1 | A<B> a = new A(); |
首先创建类A的对象,类型约束为B。创建类B的对象,与A绑定。输出类A对象中绑定类的名称。
将类A对象序列化成json字符串,然后使用反序列化方法解析出原始对象。
此时再次输出类A对象中绑定类的名称,奇怪的是为何类型绑定出现问题。
与之同时调用该绑定类的某个获取属性值的方法,就会抛出类型转换异常。
解决思路
首先看一下当前使用的反序列话方法的API。
1 | public static <T> T parseObject(String text, Class<T> clazz, Feature... features) { |
我们的需求是将序列化后的字符串反序列化成保留原始类型的对象,然而这个API的第二个参数为一个Class类型,需要传入目标对象的原始class对象。
这就会出现一个问题,泛型限定类表丢失,类型被擦除,根据java编译器的类型擦出原则,所有泛型类都会被擦除为Object类型,因为虚拟机不认泛型类。有的同学说了:怎么不可以啊,第二个参数我传Class.class 不可以么? 答案是不可以。别问为什么,Google去
说到这可以看得出,这个API不支持泛型类反序列化。那么我们在看一下关于fastJSON给出的反序列化工具还有什么?难道这是阿里在开发fastJSON时忽略的东西么?针对这个问题,我又搜索了一下,发现了如下API
1 | public static <T> T parseObject(String text, TypeReference<T> type, Feature... features); |
此API与我们使用的唯一不同的是,第二个参数使用了一个泛型类,TypeReference<T>
,哇爽的一B,然而就在我点进去想看看这个类的API文档时,我去年买了个表!毛也没有。(后来我搜了一下项目仓库找到了,在参考资料处贴出)
1 | public class TypeReference<T> { |
这个类将构造方法设置为 protected
,很明显希望我去搞个类做(继)你(承)小(你)弟(呀),哪有呢么容易说继承就继承,让我先了解清楚。这个类有个私有常量,也提供了获取方法,在构造方法中,意图很明显,希望拿到大哥类型限定列表中的类型值。那好吧,既然你这么想当大哥,那就给你个机会。
旁白:“你真要做他小弟?”
我:“绝不,给他另找一个就得了”
新的实现方式如下A a = new A();
1 | B b = new B(); |
搞定!
总结
- 在序列化和反序列化过程中带有泛型类要特别注意类型擦出的问题,尽量使用支持泛型处理的序列化和反序列化API
- 通过出现的问题来锻炼自己解决问题的能力,实在不行Google呗,千万别用百度!千万别用百度!千万别用百度!
- 别随便做人小弟,都是出来混的,有事儿解决事儿,千万别委屈求全!滥用继承,只会让代码更臃肿