關於Gson沒法將匿名類轉化爲json字符串的問題

在使用gson過程當中,通常會將數據存在一個對象模型中,使用gson將模型轉換成json字符串用於數據交互。html

代碼形如:java

        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));

程序輸出內容爲:json

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

 

可是當轉化對象是匿名類時:ide

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

程序輸出內容爲:ui

isAnonymousClass list to json is : null

 

同理,若是使用模型對象,模型的某個字段的實例對象爲匿名類,這個字段序列化的結果也是null。this

這裏咱們研究一下gson的實現來分析緣由:google

首先,經過gson.toJson方法的實現很容易招到com.google.gson.Gson#toJson(java.lang.Object, java.lang.reflect.Type, com.google.gson.stream.JsonWriter) 這個方法,實現以下:spa

  /**
   * 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方法code

 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實例,htm

這裏咱們關注的是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

相關文章
相關標籤/搜索