美文网首页
关于Gson的几个坑

关于Gson的几个坑

作者: 一只白羊座的猫 | 来源:发表于2020-03-13 10:01 被阅读0次

    为何有些序列化的结果出乎你想象?

    废话不多说,直接上正文

    1. 坑1:我们初始化Map之类的集合的时候会用如下优雅的方式:

      Map<String, String> map = new HashMap<String, String>() {
          {
           put("cat", "cat");
          }
      };
      Gson gson = new Gson();
      System.out.println(gson.toJson(map));
      

      但是会发现序列化后为null;这是因为上述方式产生的map是匿名内部类的实例,也就是说new出来的map没有类名。原因:com.google.gson.internal.Excluder#create,看源码得知Gson不序列化匿名和局部类。

      为何要这样设计呢?在github/gson的issues中找到了相关的描述(gson/issues/298),这里好像是说内部类的适配器会生成对外部类/实例的隐式引用,会导致循环引用(英语不好,应该是这样描述...)

    2. 坑2:

      Map<String, String> map = new HashMap<String, String>() {
          {
           put("cat", "cat");
          }
      };
      Set<Map.Entry<String, String>> set2 = map.entrySet();
      Gson gson = new Gson();
      System.out.println(gson.toJson(set2))
      

      结果为[{}],如上也是无法转换json的,原因看源码:com.google.gson.internal.bind.ReflectiveTypeAdapterFactory#getBoundFields

      if (raw.isInterface()) { // 这里raw是“集合元素”的类型,为java.util.Map.Entry,是一个接口!
       return result;
      }
      

      这里的map就算是普通的map(不使用构造代码块),也有一样的问题。因此,集合的泛型不要用接口、匿名内部类(匿名内部类会有坑1的问题,序列化结果为[null])。

    3. 阿里的fastjson不会有上述问题

      稍微看一下fastjson的底层实现:

      com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer(java.lang.Class<?>)

      这里调用了几个方法:

      1. buildBeanInfo,这里有个参数fieldBased默认为false,因此会调用computeGetters方法
      2. createASMSerializer(beanInfo)

      大概可以看出来在序列化的时候,先利用反射找到对象类的所有get方法,接下来去get,然后小写化,作为json的每个key值,而get方法的返回值作为value。接下来再反射field,添加到json中。

    附:上文的测试代码 > metis-json-test

    原文章:Ariescat Blog-关于Gson的几个坑

    相关文章

      网友评论

          本文标题:关于Gson的几个坑

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