FastJson TypeReference 缓存「建议收藏」

FastJson TypeReference 缓存「建议收藏」一直用FastJson做rest接口的序列化,FastJson对泛型的支持也非常好。经过一段时间使用后发现不定时的会报JsonObjectcan’tcovertto****的错误,但是重启之后就好了。排查过程不赘述,直接上代码演示StringitemJsonStr="{\"models\":{\"_defaultModel\":{\"id\":824,\&q

大家好,又见面了,我是你们的朋友全栈君。

一直用FastJson 做rest接口的序列化,FastJson对泛型的支持也非常好。经过一段时间使用后发现不定时的会报JsonObject can’t covert to ****的错误,但是重启之后就好了。排查过程不赘述,直接上代码演示

String itemJsonStr = "{\"models\":{\"_defaultModel\":{\"id\":824,\"itemName\":\"【特惠】花王L54尿不湿\",\"itemStatus\":1,\"itemPrice\":null,\"itemStock\":1511,\"categoryId\":\"69aefe645dc0482dbced7a234f71e0a9\",\"brandId\":\"e096294ba3db4703972f26ce82d64692\",\"expand\":null,\"ytItemNo\":\"MDJPHW-L54TH\",\"remarks\":\"\",\"locality\":\"日本\",\"spec\":\"包装\",\"pictures\":[\"http://staticonline.hipac.cn/item/201511/11231324205997.jpg\",\"http://staticonline.hipac.cn/item/201511/11231324204657.jpg\"],\"otherPictures\":[\"http://staticonline.hipac.cn/item/201511/11231324200849.jpg\"],\"itemDescribe\":\"偏远地区不发货。日本销量No.1纸尿裤品牌,日本原装进口,海关监管,保税区直供!专利凹凸网状织物表面,3倍透气,牢牢锁住稀软便便,让小屁屁持久干爽舒适。表层纤维添加天然植物精华,温柔呵护宝宝娇嫩肌肤。适合体重在9-14kg的宝宝。\",\"netPrice\":null,\"transitFee\":null,\"minPrice\":0.1,\"taxRate\":0.1,\"taxAmount\":null,\"guidePrice\":null,\"specificationTOs\":[],\"createTime\":1448256261000,\"editTime\":1451300191000,\"itemChannel\":\"0\",\"specialShopId\":\"0\",\"prompt\":\"\",\"keyWord\":\"每周特惠,花王,L54,尿不湿\"}},\"message\":\"\",\"code\":\"200\",\"totalCount\":0,\"success\":true,\"defaultModel\":{\"id\":824,\"itemName\":\"【特惠】花王L54尿不湿\",\"itemStatus\":1,\"itemPrice\":null,\"itemStock\":1511,\"categoryId\":\"69aefe645dc0482dbced7a234f71e0a9\",\"brandId\":\"e096294ba3db4703972f26ce82d64692\",\"expand\":null,\"ytItemNo\":\"MDJPHW-L54TH\",\"remarks\":\"\",\"locality\":\"日本\",\"spec\":\"包装\",\"pictures\":[\"http://staticonline.hipac.cn/item/201511/11231324205997.jpg\",\"http://staticonline.hipac.cn/item/201511/11231324204657.jpg\"],\"otherPictures\":[\"http://staticonline.hipac.cn/item/201511/11231324200849.jpg\"],\"itemDescribe\":\"偏远地区不发货。日本销量No.1纸尿裤品牌,日本原装进口,海关监管,保税区直供!专利凹凸网状织物表面,3倍透气,牢牢锁住稀软便便,让小屁屁持久干爽舒适。表层纤维添加天然植物精华,温柔呵护宝宝娇嫩肌肤。适合体重在9-14kg的宝宝。\",\"netPrice\":null,\"transitFee\":null,\"minPrice\":0.1,\"taxRate\":0.1,\"taxAmount\":null,\"guidePrice\":null,\"specificationTOs\":[],\"createTime\":1448256261000,\"editTime\":1451300191000,\"itemChannel\":\"0\",\"specialShopId\":\"0\",\"prompt\":\"\",\"keyWord\":\"每周特惠,花王,L54,尿不湿\"}}";
 
        //下面这行注释掉第二打印出来就是true
        ResultData<?> resultFromClass = JSONObject.parseObject(itemJsonStr, new TypeReference<ResultData>() {
        });
        System.out.println(resultFromClass.getDefaultModel() instanceof JSONObject);
        ResultData<?> itemResult = JSONObject.parseObject(itemJsonStr, new TypeReference<ResultData<ItemTO>>() {}.getType());
        System.out.println(itemResult.getDefaultModel() instanceof ItemTO);

这样打印出来的结果是true,false。但是把第一个parseObject 注释掉,第二个就打印出true。大致debug了下FastJson的代码,大概定位到问题应该是出现对类解析的缓存上
ParserConfig.java,getDeserializer方法

        if (type instanceof Class<?>) {
            return getDeserializer((Class<?>) type, type);
        }
 
        if (type instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) type).getRawType();
            if (rawType instanceof Class<?>) {
                return getDeserializer((Class<?>) rawType, type);
            } else {
                return getDeserializer(rawType);
            }
        }

第一个if 判断是否是class,第二个if是判断是否泛型类型,getRawType 是获取泛型的类型,然后进入getDeserializer 方法,这个方法里有一个缓存

if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) {
            derializer = derializers.get(clazz);
        }

缓存的放入是在putDeserializer 这个方法

public void putDeserializer(Type type, ObjectDeserializer deserializer) {
        derializers.put(type, deserializer);
    }

可以看到缓存的key是Type.
由此引发的问题:首先解析new TypeReference() ,走了getDeserializer 的第一个if,这样putDeserializer方法里放入的是ResultData。接着解析new TypeReference<ResultData>(),这个时候走了getDeserializer 的第二个if,结果rawType是ResultData,所以直接从缓存中返回了第一次解析的结果。这样就相当于丢失了泛型类型ItemTO,导致最后类型转换失败。使用中偶现的原因是大部分ResultData都有泛型,只有非常少的ResultData没有泛型,因此当调用了没有泛型的ResultData之后,就会出现错误。

解决方案:统一使用泛型类型,项目中不允许没有泛型类型的ResultData,就不会存在这个问题。
我现在的解决方案是 jar包上最新的jar就可以了…人家修复了

作者:ykdsg
来源:CSDN
原文:https://blog.csdn.net/ykdsg/article/details/50432494
版权声明:本文为博主原创文章,转载请附上博文链接!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150462.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Mysql Connector C++ 在VS2008下编译[通俗易懂]

    Mysql Connector C++ 在VS2008下编译[通俗易懂]1、安装Mysql下载http://dev.mysql.com/downloads/windows/installer/,安装即可2、安装完成之后找到安装目录下有ConnectorC++1.1.3目录,目录下有include和lib文件夹在vs2008中将include路径包含进来:再把lib路径包含进来:再将mysqlcppconn.lib库以及mysql

    2022年7月27日
    6
  • 【Android】Android游戏编程之从零开始[通俗易懂]

    【Android】Android游戏编程之从零开始[通俗易懂]《Android游戏编程之从零开始》主要系统地讲解了Android游戏开发,从最基础部分开始,让零基础的Android初学者也能快速学习和掌握Android游戏开发。《Android游戏编程之从零开始》一共8章,内容包括Android平台介绍与环境搭建、Hello,Android!项目剖析、游戏开发中常用的系统组件、游戏开发基础、游戏开发实战、游戏开发提高篇、Box2d物理引擎、物…

    2022年5月27日
    204
  • PyCharm激活码永久有效PyCharm2021.3.2激活码教程-持续更新,一步到位

    PyCharm激活码永久有效PyCharm2021.3.2激活码教程-持续更新,一步到位PyCharm激活码永久有效2021.3.2激活码教程-Windows版永久激活-持续更新,Idea激活码2021.3.2成功激活

    2022年6月19日
    109
  • Expression Web设计工具

    Expression Web设计工具

    2021年7月24日
    60
  • LeetCode报错:AddressSanitizer:DEADLYSIGNAL详细分析与解决

    LeetCode报错:AddressSanitizer:DEADLYSIGNAL详细分析与解决LeetCode报错:AddressSanitizer:DEADLYSIGNAL详细分析与解决问题描述问题分析实例分析更多总结见:C刷题:LeetCode刷题踩坑常见BUG总结问题描述报错:AddressSanitizer:DEADLYSIGNAL,详细如下===42====ERROR:AddressSanitizer:SEGVonunknownaddressxx.ThesignaliscausedbyaREADmemoryaccess.问题分析一般可能主要有

    2022年10月24日
    0
  • 苹果手机数据转移到新手机_不同品牌手机一键换机:换新手机怎么转移数据?…

    苹果手机数据转移到新手机_不同品牌手机一键换机:换新手机怎么转移数据?…我们正处于一个数码产品更新换代非常快速的时代,很多消费者会紧跟时代潮流,经常更换新手机,但是更换手机之后我们通常需要将旧手机里的数据进行转移,不同品牌之间的手机怎么进行一键换机呢?以安卓手机更换苹果手机转移数据为例:1、首先我们需要在安卓手机上安装“转移到iOS”APP,通过该应用我们可以将安卓手机的数据转移到新的苹果手机上2、确保安卓设备处于WiFi状态3、将安卓设备以及苹果设备连接电源4、设置…

    2022年5月25日
    39

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号