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
|
* @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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user