Don't use ThreadLocals for @JsonAdapter factories and getDelegateAdapter().

This commit is contained in:
jwilson 2016-06-02 00:18:03 -04:00
parent 943c674276
commit 2df65502ed
4 changed files with 30 additions and 82 deletions

View File

@ -488,26 +488,28 @@ public final class Gson {
* @since 2.2
*/
public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) {
// If the specified skipPast factory is not registered, ignore it.
boolean skipPastFound = skipPast == null
|| (!factories.contains(skipPast) && jsonAdapterFactory.getDelegateAdapterFactory(type) == null);
boolean skipPastFound = false;
// Hack. If the skipPast factory isn't registered, assume the factory is being requested via
// our @JsonAdapter annotation.
if (!factories.contains(skipPast)) {
skipPast = jsonAdapterFactory;
}
for (TypeAdapterFactory factory : factories) {
if (!skipPastFound) {
skipPastFound = factory == skipPast;
if (!skipPastFound && factory instanceof JsonAdapterAnnotationTypeAdapterFactory) {
// Also check if there is a registered JsonAdapter for it
factory = ((JsonAdapterAnnotationTypeAdapterFactory)factory).getDelegateAdapterFactory(type);
skipPastFound = factory == skipPast;
if (factory == skipPast) {
skipPastFound = true;
}
continue;
}
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot serialize or deserialize " + type);
throw new IllegalArgumentException("GSON cannot serialize " + type);
}
/**

View File

@ -16,9 +16,6 @@
package com.google.gson.internal.bind;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSerializer;
@ -35,15 +32,6 @@ import com.google.gson.reflect.TypeToken;
* @since 2.3
*/
public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("rawtypes")
private final ThreadLocal<Map<Class, TypeAdapterFactory>> activeJsonAdapterFactories = new ThreadLocal<Map<Class, TypeAdapterFactory>>() {
@Override protected Map<Class, TypeAdapterFactory> initialValue() {
// No need for a thread-safe map since we are using it in a single thread
return new HashMap<Class, TypeAdapterFactory>();
}
};
private final ConstructorConstructor constructorConstructor;
public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
@ -61,75 +49,34 @@ public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapte
return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation);
}
public <T> TypeAdapter<T> getDelegateAdapter(Gson gson, TypeAdapterFactory skipPast, TypeToken<T> targetType) {
TypeAdapterFactory factory = getDelegateAdapterFactory(targetType);
if (factory == skipPast) factory = null;
return factory == null ? null: factory.create(gson, targetType);
}
public <T> TypeAdapterFactory getDelegateAdapterFactory(TypeToken<T> targetType) {
Class<?> annotatedClass = targetType.getRawType();
JsonAdapter annotation = annotatedClass.getAnnotation(JsonAdapter.class);
if (annotation == null) {
return null;
}
return getTypeAdapterFactory(annotation, constructorConstructor);
}
@SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals.
TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson,
TypeToken<?> type, JsonAdapter annotation) {
Class<?> value = annotation.value();
boolean isTypeAdapter = TypeAdapter.class.isAssignableFrom(value);
boolean isJsonSerializer = JsonSerializer.class.isAssignableFrom(value);
boolean isJsonDeserializer = JsonDeserializer.class.isAssignableFrom(value);
Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct();
TypeAdapter<?> typeAdapter;
if (isTypeAdapter || isJsonSerializer || isJsonDeserializer) {
if (isTypeAdapter) {
Class<TypeAdapter<?>> typeAdapterClass = (Class<TypeAdapter<?>>) value;
typeAdapter = constructorConstructor.get(TypeToken.get(typeAdapterClass)).construct();
} else if (isJsonSerializer || isJsonDeserializer) {
JsonSerializer serializer = null;
if (isJsonSerializer) {
Class<JsonSerializer<?>> serializerClass = (Class<JsonSerializer<?>>) value;
serializer = constructorConstructor.get(TypeToken.get(serializerClass)).construct();
}
JsonDeserializer deserializer = null;
if (isJsonDeserializer) {
Class<JsonDeserializer<?>> deserializerClass = (Class<JsonDeserializer<?>>) value;
deserializer = constructorConstructor.get(TypeToken.get(deserializerClass)).construct();
}
typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
} else {
typeAdapter = null;
}
} else if (TypeAdapterFactory.class.isAssignableFrom(value)) {
TypeAdapterFactory factory = getTypeAdapterFactory(annotation, constructorConstructor);
typeAdapter = factory == null ? null : factory.create(gson, type);
if (instance instanceof TypeAdapter) {
typeAdapter = (TypeAdapter<?>) instance;
} else if (instance instanceof TypeAdapterFactory) {
typeAdapter = ((TypeAdapterFactory) instance).create(gson, type);
} else if (instance instanceof JsonSerializer || instance instanceof JsonDeserializer) {
JsonSerializer<?> serializer = instance instanceof JsonSerializer
? (JsonSerializer) instance
: null;
JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer
? (JsonDeserializer) instance
: null;
typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
} else {
throw new IllegalArgumentException(
"@JsonAdapter value must be TypeAdapter, TypeAdapterFactory, JsonSerializer or JsonDeserializer reference.");
"@JsonAdapter value must be TypeAdapter, TypeAdapterFactory, "
+ "JsonSerializer or JsonDeserializer reference.");
}
if (typeAdapter != null) {
typeAdapter = typeAdapter.nullSafe();
}
return typeAdapter;
}
@SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals.
TypeAdapterFactory getTypeAdapterFactory(JsonAdapter annotation, ConstructorConstructor constructorConstructor) {
Class<?> value = annotation.value();
if (!TypeAdapterFactory.class.isAssignableFrom(value)) return null;
Map<Class, TypeAdapterFactory> adapterFactories = activeJsonAdapterFactories.get();
TypeAdapterFactory factory = adapterFactories.get(value);
if (factory == null) {
Class<TypeAdapterFactory> typeAdapterFactoryClass = (Class<TypeAdapterFactory>) value;
factory = constructorConstructor.get(TypeToken.get(typeAdapterFactoryClass))
.construct();
adapterFactories.put(value, factory);
}
return factory;
}
}

View File

@ -32,7 +32,6 @@ import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
@ -110,7 +109,7 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
TypeAdapter<?> mapped = null;
if (annotation != null) {
mapped = jsonAdapterFactory.getTypeAdapter(
constructorConstructor, context, fieldType, annotation);
constructorConstructor, context, fieldType, annotation);
}
final boolean jsonAdapterPresent = mapped != null;
if (mapped == null) mapped = context.getAdapter(fieldType);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 Google Inc.
* Copyright (C) 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.