2017年11月22日 星期三

解决使用FastJson反序列化泛型类时,内部嵌套类型无法正确识别的问题

java 耗子睡着了 275阅读 0评论

在开发中经常会遇到序列化和反序列化的问题,比较常用的是将对象序列化成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。

搞一下

首先创建类A的对象,类型约束为B。创建类B的对象,与A绑定。输出类A对象中绑定类的名称。

将类A对象序列化成json字符串,然后使用反序列化方法解析出原始对象。

此时再次输出类A对象中绑定类的名称,奇怪的是为何类型绑定出现问题。

与之同时调用该绑定类的某个获取属性值的方法,就会抛出类型转换异常。

解决思路

首先看一下当前使用的反序列话方法的API。

我们的需求是将序列化后的字符串反序列化成保留原始类型的对象,然而这个API的第二个参数为一个Class类型,需要传入目标对象的原始class对象。

这就会出现一个问题,泛型限定类表丢失,类型被擦除,根据java编译器的类型擦出原则,所有泛型类都会被擦除为Object类型,因为虚拟机不认泛型类。有的同学说了:怎么不可以啊,第二个参数我传Class<B>.class 不可以么? 答案是不可以。别问为什么,Google去

说到这可以看得出,这个API不支持泛型类反序列化。那么我们在看一下关于fastJSON给出的反序列化工具还有什么?难道这是阿里在开发fastJSON时忽略的东西么?针对这个问题,我又搜索了一下,发现了如下API

此API与我们使用的唯一不同的是,第二个参数使用了一个泛型类,TypeReference<T>,哇爽的一B,然而就在我点进去想看看这个类的API文档时,我去年买了个表!毛也没有。(后来我搜了一下项目仓库找到了,在参考资料处贴出)

这个类将构造方法设置为 protected,很明显希望我去搞个类做(继)你(承)小(你)弟(呀),哪有呢么容易说继承就继承,让我先了解清楚。这个类有个私有常量,也提供了获取方法,在构造方法中,意图很明显,希望拿到大哥类型限定列表中的类型值。那好吧,既然你这么想当大哥,那就给你个机会。

旁白:“你真要做他小弟?”

我:“绝不,给他另找一个就得了”

新的实现方式如下A<B> a = new A();

搞定!

总结

  1. 在序列化和反序列化过程中带有泛型类要特别注意类型擦出的问题,尽量使用支持泛型处理的序列化和反序列化API
  2. 通过出现的问题来锻炼自己解决问题的能力,实在不行Google呗,千万别用百度!千万别用百度!千万别用百度!
  3. 别随便做人小弟,都是出来混的,有事儿解决事儿,千万别委屈求全!滥用继承,只会让代码更臃肿

参考资料

 

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址