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 * @since 2.2
*/ */
public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) { public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) {
// If the specified skipPast factory is not registered, ignore it. boolean skipPastFound = false;
boolean skipPastFound = skipPast == null
|| (!factories.contains(skipPast) && jsonAdapterFactory.getDelegateAdapterFactory(type) == null); // 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) { for (TypeAdapterFactory factory : factories) {
if (!skipPastFound) { if (!skipPastFound) {
skipPastFound = factory == skipPast; if (factory == skipPast) {
if (!skipPastFound && factory instanceof JsonAdapterAnnotationTypeAdapterFactory) { skipPastFound = true;
// Also check if there is a registered JsonAdapter for it
factory = ((JsonAdapterAnnotationTypeAdapterFactory)factory).getDelegateAdapterFactory(type);
skipPastFound = factory == skipPast;
} }
continue; continue;
} }
TypeAdapter<T> candidate = factory.create(this, type); TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) { if (candidate != null) {
return candidate; 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; package com.google.gson.internal.bind;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonDeserializer; import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;
@ -35,15 +32,6 @@ import com.google.gson.reflect.TypeToken;
* @since 2.3 * @since 2.3
*/ */
public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapterFactory { 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; private final ConstructorConstructor constructorConstructor;
public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) { public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
@ -61,75 +49,34 @@ public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapte
return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation); 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. @SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals.
TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson, TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson,
TypeToken<?> type, JsonAdapter annotation) { TypeToken<?> type, JsonAdapter annotation) {
Class<?> value = annotation.value(); Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct();
boolean isTypeAdapter = TypeAdapter.class.isAssignableFrom(value);
boolean isJsonSerializer = JsonSerializer.class.isAssignableFrom(value);
boolean isJsonDeserializer = JsonDeserializer.class.isAssignableFrom(value);
TypeAdapter<?> typeAdapter; TypeAdapter<?> typeAdapter;
if (isTypeAdapter || isJsonSerializer || isJsonDeserializer) { if (instance instanceof TypeAdapter) {
if (isTypeAdapter) { typeAdapter = (TypeAdapter<?>) instance;
Class<TypeAdapter<?>> typeAdapterClass = (Class<TypeAdapter<?>>) value; } else if (instance instanceof TypeAdapterFactory) {
typeAdapter = constructorConstructor.get(TypeToken.get(typeAdapterClass)).construct(); typeAdapter = ((TypeAdapterFactory) instance).create(gson, type);
} else if (isJsonSerializer || isJsonDeserializer) { } else if (instance instanceof JsonSerializer || instance instanceof JsonDeserializer) {
JsonSerializer serializer = null; JsonSerializer<?> serializer = instance instanceof JsonSerializer
if (isJsonSerializer) { ? (JsonSerializer) instance
Class<JsonSerializer<?>> serializerClass = (Class<JsonSerializer<?>>) value; : null;
serializer = constructorConstructor.get(TypeToken.get(serializerClass)).construct(); JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer
} ? (JsonDeserializer) instance
JsonDeserializer deserializer = null; : null;
if (isJsonDeserializer) { typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
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);
} else { } else {
throw new IllegalArgumentException( 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) { if (typeAdapter != null) {
typeAdapter = typeAdapter.nullSafe(); typeAdapter = typeAdapter.nullSafe();
} }
return typeAdapter; 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.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -110,7 +109,7 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
TypeAdapter<?> mapped = null; TypeAdapter<?> mapped = null;
if (annotation != null) { if (annotation != null) {
mapped = jsonAdapterFactory.getTypeAdapter( mapped = jsonAdapterFactory.getTypeAdapter(
constructorConstructor, context, fieldType, annotation); constructorConstructor, context, fieldType, annotation);
} }
final boolean jsonAdapterPresent = mapped != null; final boolean jsonAdapterPresent = mapped != null;
if (mapped == null) mapped = context.getAdapter(fieldType); 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.