예제 #1
0
  /**
   * This method is used to get an alternate type adapter for the specified type. This is used to
   * access a type adapter that is overridden by a {@link TypeAdapterFactory} that you may have
   * registered. This features is typically used when you want to register a type adapter that does
   * a little bit of work but then delegates further processing to the Gson default type adapter.
   * Here is an example:
   *
   * <p>Let's say we want to write a type adapter that counts the number of objects being read from
   * or written to JSON. We can achieve this by writing a type adapter factory that uses the <code>
   * getDelegateAdapter</code> method:
   *
   * <pre>{@code
   * class StatsTypeAdapterFactory implements TypeAdapterFactory {
   *   public int numReads = 0;
   *   public int numWrites = 0;
   *   public &lt;T&gt; TypeAdapter&lt;T&gt; create(Gson gson, TypeToken&lt;T&gt; type) {
   *     final TypeAdapter&lt;T&gt; delegate = gson.getDelegateAdapter(this, type);
   *     return new TypeAdapter&lt;T&gt;() {
   *       public void write(JsonWriter out, T value) throws IOException {
   *         ++numWrites;
   *         delegate.write(out, value);
   *       }
   *       public T read(JsonReader in) throws IOException {
   *         ++numReads;
   *         return delegate.read(in);
   *       }
   *     };
   *   }
   * }
   * }
   * </pre>
   *
   * This factory can now be used like this:
   *
   * <pre>{@code
   * StatsTypeAdapterFactory stats = new StatsTypeAdapterFactory();
   * Gson gson = new GsonBuilder().registerTypeAdapterFactory(stats).create();
   * // Call gson.toJson() and fromJson methods on objects
   * System.out.println("Num JSON reads" + stats.numReads);
   * System.out.println("Num JSON writes" + stats.numWrites);
   *
   * }</pre>
   *
   * Note that since you can not override type adapter factories for String and Java primitive
   * types, our stats factory will not count the number of String or primitives that will be read or
   * written.
   *
   * @param skipPast The type adapter factory that needs to be skipped while searching for a
   *     matching type adapter. In most cases, you should just pass <i>this</i> (the type adapter
   *     factory from where {@link #getDelegateAdapter} method is being invoked).
   * @param type Type for which the delegate adapter is being searched for.
   * @since 2.2
   */
  public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) {
    boolean skipPastFound = false;

    for (TypeAdapterFactory factory : factories) {
      if (!skipPastFound) {
        if (factory == skipPast) {
          skipPastFound = true;
        }
        continue;
      }

      TypeAdapter<T> candidate =
          factory.create(
              new AdapterCreator() {

                @Override
                public TypeAdapter<Object> getAdapter(Class<? extends Object> class1) {
                  return this.getAdapter(class1);
                }

                @Override
                public TypeAdapter<?> getAdapter(TypeToken<?> typeToken) {
                  return this.getAdapter(typeToken);
                }

                @Override
                public <T> TypeAdapter<T> getDelegateAdapter(
                    TypeAdapterFactory skipPast, TypeToken<T> type) {
                  // TODO Auto-generated method stub
                  return null;
                }
              },
              type);
      if (candidate != null) {
        return candidate;
      }
    }
    throw new IllegalArgumentException("GSON cannot serialize " + type);
  }
예제 #2
0
  /**
   * Returns the type adapter for {@code} type.
   *
   * @throws IllegalArgumentException if this GSON cannot serialize and deserialize {@code type}.
   */
  @SuppressWarnings("unchecked")
  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);
        TypeAdapter<T> candidate =
            factory.create(
                new AdapterCreator() {

                  @Override
                  public TypeAdapter<?> getAdapter(TypeToken<?> typeToken) {
                    return this.getAdapter(typeToken);
                  }

                  @Override
                  public TypeAdapter<Object> getAdapter(Class<? extends Object> class1) {
                    return this.getAdapter(class1);
                  }

                  @Override
                  public <T> TypeAdapter<T> getDelegateAdapter(
                      TypeAdapterFactory skipPast, TypeToken<T> type) {
                    // TODO Auto-generated method stub
                    return null;
                  }
                },
                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();
      }
    }
  }