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

之前一直是用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解析库!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,323评论 19 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,149评论 25 709
  • 你来人间一趟,你要看看太阳,和你的心上人,一起走在街上。 ...
    橘子墨野阅读 1,189评论 0 2
  • 案主信息:和煦的午后,小鸟在天空溜达,鱼儿在水中散步,花儿随着拂面微风的律动在歌唱,我在自己小院的树下读书。 分析...
    奶茶干妈阅读 1,287评论 0 0