加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

FastJson 泛型转换踩坑

发布时间:2020-12-16 19:01:07 所属栏目:百科 来源:网络整理
导读:一直用FastJson 做rest接口的序列化,FastJson对泛型的支持也非常好。经过一段时间使用后发现不定时的会报JsonObject can't covert to ****的错误,但是重启之后就好了。排查过程不赘述,直接上代码演示 String itemJsonStr = "{"models":{"_defaultModel

一直用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,尿不湿"}}";

        //下面这行注释掉第二打印出来就是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<ResultData>() ,走了getDeserializer 的第一个if,这样putDeserializer方法里放入的是ResultData。接着解析new TypeReference<ResultData<ItemTO>>(),这个时候走了getDeserializer 的第二个if,结果rawType是ResultData,所以直接从缓存中返回了第一次解析的结果。这样就相当于丢失了泛型类型ItemTO,导致最后类型转换失败。使用中偶现的原因是大部分ResultData都有泛型,只有非常少的ResultData没有泛型,因此当调用了没有泛型的ResultData之后,就会出现错误。

解决方案:统一使用泛型类型,项目中不允许没有泛型类型的ResultData,就不会存在这个问题。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读