美文网首页第三方扩展
在用FastJson序列数据化转换时踩坑经验

在用FastJson序列数据化转换时踩坑经验

作者: 小木桨 | 来源:发表于2016-06-24 17:27 被阅读3038次

    之前一直是用Gson做数据序列化,后来换工作后新公司是用fastJson做序列化的,在做网络框架优化后,不定时的会抛出JsonObject can't covert to **** 异常,各种排查后发现是fastJson的问题,下面一步一步来分析:

    原始json数据:

    //登录前
    {"code":200,"msg":"成功","data":[]}
    //登录后
    {"code":200,"msg":"成功","data":{"count":0}}
    

    解析json代码:

    static CommonResponse responseConvert(String json, Type clz){
               JSONObject object = new JSONObject(json);
               String data = object.optString(DATA);
               if(TextUtils.isEmpty(data) || "[]".equals(data) || "{}".equals(data) ){
                CommonResponse resp =  JSON.parseObject(json, CommonResponse.class);
               ....
               return resp;
               }else{
               return JSON.parseObject(json,clz)
               }
    }
    

    分析原因:

    从代码上来看应该没问题,看不出什么问题,首先判断json的data字段是否为空或是否为空数组,如果是空则使用默认的CommonResponse类去解析,如果不为空则使用CommonResponse<T>泛型的方式去解析,如果data字段一直为空或一直不为空都不会有问题,但如果从空变成有数据后就出现了上面的异常,通过查看fastJson源码才发现问题所在:
    ParserConfig.Java

    public ObjectDeserializer getDeserializer(Type type) {
         ...省略无关代码
    
          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);
              }
          }
          return JavaObjectDeserializer.instance;
      }
    

    通过源码可以看到,首先判断参数type是否为Class,如果是则进入getDeserializer方法,如果不是则继续判断参数是否为泛型,getRawType是获取泛型类型,如果泛型里面没有再嵌套泛型了则也进入getDeserializer方法,如果还有则进行递归调用,直到拿到最里面泛型为止,继续看getDeserializer方法:

    public ObjectDeserializer getDeserializer(Class<?> clazz, Type type) {
           ...省略无关代码
            if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) {
                derializer = derializers.get(clazz);
            }
    
            if (derializer != null) {
                return derializer;
            }
            ...省略无关代码
            putDeserializer(type, derializer);
            return derializer;
     }
    

    在getDeserializer方法中会先去判断缓存中是否已存储这个参数Class如果有则直接用缓存中的,如果没有则添加到缓存中。
     代码看到这里也就发现问题所在了,原因:首先在第一次解析CommonResponse的时候走的是getDeserializer的第一个if,然后缓存起来这个CommonResponse,接着在登录后,data字段数据类型发生了改变,变成CommonResponse<T>类型,所以解析的走的是第二个if,结果rawType是CommonResponse,所以直接从缓存中返回了第一次解析的结果,这样就相当于丢失了CommonResponse中的泛型<T>,所以导致最后类型转换失败!

    总结

    统一使用泛型类型,不允许没有泛型类型的CommonResponse,如果不能统一泛型类型的,最好换一个Json解析库!

    相关文章

      网友评论

        本文标题:在用FastJson序列数据化转换时踩坑经验

        本文链接:https://www.haomeiwen.com/subject/hmgodttx.html