fastjson反序列化多层嵌套泛型类与java中的Type类型(转)详细版本

https://www.cnblogs.com/liqipeng/p/9148545.html

fastjson反序列化多层嵌套泛型类与java中的Type类型

在使用springmvc时,我们通常会定义类似这样的通用类与前端进行交互,以便于前端可以做一些统一的处理:

publicclassResult{privateintret;privateString msg;privateT data;// 此处省略getter和setter方法}

这样的类序列化为json后,js反序列化处理起来毫无压力。但是如果rest接口的消费端就是java呢,java泛型的类型擦除却容易引入一些障碍。

一个反序列化的迭代

先定义一个类,后面的例子会用到:

publicclassItem{privateString name;privateStringvalue;// 此处省略getter和setter方法}

JSON数据:

{"data":{"name":"username","value":"root"},"msg":"Success","ret":0}

当拿到上面的数据时,我们想到其对应的类型是Result,所以得想办法将这个json数据反序列化为这个类型才行。

v1

JSONObject.parseObject(json, Result.class);,编译器就报错了Cannot select parameterized type。

v2

JSONObject.parseObject(json, Result.class);,执行没问题。但是没有Item类型信息,fastjson不可能跟你心有灵犀一点通知道该把data转为Item类型,result.getData().getClass()结果是com.alibaba.fastjson.JSONObject,也算是个妥善处理吧。

v3

找了一下前人的经验,使用TypeReference来处理,JSONObject.parseObject(json, new TypeReference>(){});,终于“完美”解决!

v4

有了v3的经验,以为找到了通用处理的捷径,遂封装了一个处理这种类型的工具方法:

privatestaticResultparseResultV1(String json){returnJSONObject.parseObject(json,newTypeReference>() {    });}

并且把采用v3的地方改用了此parseResult方法:

Result<<span class="hljs-name" style="margin: 0px; padding: 0px;">Item>result = parseResultV1(json);

以为万事大吉,连测都没测试就把代码提交了。测都不测试,当然难以有好结果了:

System.out.println(result.getData());// java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to Item

很显然parseResultV1把Item的类型信息丢掉了。

{"data":"Hello,world!","msg":"Success","ret":0}

试了一下Result形式的,parseResultV1可以成功将其反序列化。推测(没有看fastjson具体实现)是fastjson刚好检测到data字段就是String类型,并将其赋值到data字段上了。仔细看parseObject并没有报错,而是在getData()时报错的,联系到,应该把data当作Object类型这么看:

Stringdata= (String)result.getData();System.out.println(data);

v5

原来TypeReference的构造器是可以传入参数的,

privatestaticResult parseResultV2(String json,Class<T>clazz){returnJSONObject.parseObject(json,newTypeReference>(clazz) {    });}

这个可以真的可以完美反序列化Result了。

v6

后来发现parseResultV2无法处理类似Result>,原来TypeReference无法处理嵌套的泛型(这里指的是类型参数未确定,而不是类似Result>类型参数已经确定)。借用Fastjson解析多级泛型的几种方式—使用class文件来解析多级泛型里的方法,新增加一个专门处理List类型的方法:

privatestaticResult<List> parseListResult(Stringjson, Class clazz) {returnJSONObject.parseObject(json, buildType(Result.class,List.class, Item.class));}privatestaticTypebuildType(Type... types) {    ParameterizedTypeImpl beforeType =null;if(types !=null&& types.length >0) {for(inti = types.length -1; i >0; i--) {            beforeType =newParameterizedTypeImpl(newType[]{beforeType ==null? types[i] : beforeType},null, types[i -1]);        }    }returnbeforeType;}

或者根据这里只有两层,简单如下:

privatestaticResult<List> parseListResult(Stringjson, Class clazz) {    ParameterizedTypeImpl inner =newParameterizedTypeImpl(newType[]{clazz},null,List.class);    ParameterizedTypeImpl outer =newParameterizedTypeImpl(newType[]{inner},null, Result.class);returnJSONObject.parseObject(json, outer);}

v7

todo: 上面两个方法已经可以满足现有需要,有时间再看看能否将两个方法统一为一个。

com.alibaba.fastjson.TypeReference

看看TypeReference的源码:

protected TypeReference(Type... actualTypeArguments) {    Class

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容