/** * 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 <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { * final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); * return new TypeAdapter<T>() { * 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); }
/** * 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(); } } }