Don't use ThreadLocals for @JsonAdapter factories and getDelegateAdapter().
This commit is contained in:
parent
943c674276
commit
2df65502ed
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user