• 关于Gson无法将匿名类转化为json字符串的问题


    在使用gson过程中,一般会将数据存在一个对象模型中,使用gson将模型转换成json字符串用于数据交互。

    代码形如:

            ArrayList<String> list =  new ArrayList<>();
            list.add("test1");
            list.add("test2");
            Gson gson = new Gson();
            System.out.println("list to json is : "+gson.toJson(list));

    程序输出内容为:

    list to json is : ["test1","test2"]

    但是当转化对象是匿名类时:

            ArrayList<String> arrayList =  new ArrayList<String>() {{
                add("对");
                add("不对");
            }};
            Gson gson = new Gson();
            System.out.println("isAnonymousClass list to json is : "+gson.toJson(arrayList));

    程序输出内容为:

    isAnonymousClass list to json is : null

    同理,如果使用模型对象,模型的某个字段的实例对象为匿名类,这个字段序列化的结果也是null。

    这里我们研究一下gson的实现来分析原因:

    首先,通过gson.toJson方法的实现很容易招到com.google.gson.Gson#toJson(java.lang.Object, java.lang.reflect.Type, com.google.gson.stream.JsonWriter) 这个方法,实现如下:

      /**
       * Writes the JSON representation of {@code src} of type {@code typeOfSrc} to
       * {@code writer}.
       * @throws JsonIOException if there was a problem writing to the writer
       */
      @SuppressWarnings("unchecked")
      public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
        TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
        boolean oldLenient = writer.isLenient();
        writer.setLenient(true);
        boolean oldHtmlSafe = writer.isHtmlSafe();
        writer.setHtmlSafe(htmlSafe);
        boolean oldSerializeNulls = writer.getSerializeNulls();
        writer.setSerializeNulls(serializeNulls);
        try {
          ((TypeAdapter<Object>) adapter).write(writer, src);
        } catch (IOException e) {
          throw new JsonIOException(e);
        } finally {
          writer.setLenient(oldLenient);
          writer.setHtmlSafe(oldHtmlSafe);
          writer.setSerializeNulls(oldSerializeNulls);
        }
      }

    进入getAdapter方法

     public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
        TypeAdapter<?> cached = typeTokenCache.get(type);
        if (cached != null) {
          return (TypeAdapter<T>) cached;
        }
    
        Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
        boolean requiresThreadLocalCleanup = false;
        if (threadCalls == null) {
          threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
          calls.set(threadCalls);
          requiresThreadLocalCleanup = true;
        }
    
        // the key and value type parameters always agree
        FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
        if (ongoingCall != null) {
          return ongoingCall;
        }
    
        try {
          FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
          threadCalls.put(type, call);
    
          for (TypeAdapterFactory factory : factories) {
            TypeAdapter<T> candidate = factory.create(this, type);
            if (candidate != null) {
              call.setDelegate(candidate);
              typeTokenCache.put(type, candidate);
              return candidate;
            }
          }
          throw new IllegalArgumentException("GSON cannot handle " + type);
        } finally {
          threadCalls.remove(type);
    
          if (requiresThreadLocalCleanup) {
            calls.remove();
          }
        }
      }
     

     这里,获取adapter时,会从默认的工厂列表中逐个获取工厂,基于传入的类型获取adapter实例,

    这里我们关注的是com.google.gson.internal.Excluder这个工厂,

      public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
        Class<?> rawType = type.getRawType();
        final boolean skipSerialize = excludeClass(rawType, true);
        final boolean skipDeserialize = excludeClass(rawType, false);
    
        if (!skipSerialize && !skipDeserialize) {
          return null;
        }
    
        return new TypeAdapter<T>() {
          /** The delegate is lazily created because it may not be needed, and creating it may fail. */
          private TypeAdapter<T> delegate;
    
          @Override public T read(JsonReader in) throws IOException {
            if (skipDeserialize) {
              in.skipValue();
              return null;
            }
            return delegate().read(in);
          }
    
          @Override public void write(JsonWriter out, T value) throws IOException {
            if (skipSerialize) {
              out.nullValue();
              return;
            }
            delegate().write(out, value);
          }
    
          private TypeAdapter<T> delegate() {
            TypeAdapter<T> d = delegate;
            return d != null
                ? d
                : (delegate = gson.getDelegateAdapter(Excluder.this, type));
          }
        };
      }

    这里

      public boolean excludeClass(Class<?> clazz, boolean serialize) {
        if (version != Excluder.IGNORE_VERSIONS
            && !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
          return true;
        }
    
        if (!serializeInnerClasses && isInnerClass(clazz)) {
          return true;
        }
    
        if (isAnonymousOrLocal(clazz)) {
          return true;
        }
    
        List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
        for (ExclusionStrategy exclusionStrategy : list) {
          if (exclusionStrategy.shouldSkipClass(clazz)) {
            return true;
          }
        }
    
        return false;
      }

    这里调用了isAnonymousOrLocal这个方法(从方法名称来看就是判断是否是匿名类或本地类,其判断是否是匿名类的逻辑是使用的java.lang.Class#isAnonymousClass方法,根据类名判断),由于skipSerialize和skipDeserialize 都由这个逻辑返回了true,最后create方法返回了Excluder工厂生成adapter对象.

    由Excluder的注释和返回的TypeAdapter对象都很容易看出,它的作用就是忽略该对象的j转换,最终返回null

  • 相关阅读:
    curd_4
    curd_2
    Python Regex库的使用
    Python Assert 确认条件为真的工具
    Python Regex库的使用(2)
    Python lambda的用法
    Python 列表综合
    with ss(date,date2) (select * from sysdummy1) select * from ss
    延迟执行函数
    ObjectiveC 的基本数据类型、数字、字符串和集合等介绍
  • 原文地址:https://www.cnblogs.com/lmsthoughts/p/8656688.html
Copyright © 2020-2023  润新知