Skip to content

Commit 2df6550

Browse files
committed
Don't use ThreadLocals for @JsonAdapter factories and getDelegateAdapter().
1 parent 943c674 commit 2df6550

File tree

4 files changed

+30
-82
lines changed

4 files changed

+30
-82
lines changed

gson/src/main/java/com/google/gson/Gson.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -488,26 +488,28 @@ public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
488488
* @since 2.2
489489
*/
490490
public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) {
491-
// If the specified skipPast factory is not registered, ignore it.
492-
boolean skipPastFound = skipPast == null
493-
|| (!factories.contains(skipPast) && jsonAdapterFactory.getDelegateAdapterFactory(type) == null);
491+
boolean skipPastFound = false;
492+
493+
// Hack. If the skipPast factory isn't registered, assume the factory is being requested via
494+
// our @JsonAdapter annotation.
495+
if (!factories.contains(skipPast)) {
496+
skipPast = jsonAdapterFactory;
497+
}
494498

495499
for (TypeAdapterFactory factory : factories) {
496500
if (!skipPastFound) {
497-
skipPastFound = factory == skipPast;
498-
if (!skipPastFound && factory instanceof JsonAdapterAnnotationTypeAdapterFactory) {
499-
// Also check if there is a registered JsonAdapter for it
500-
factory = ((JsonAdapterAnnotationTypeAdapterFactory)factory).getDelegateAdapterFactory(type);
501-
skipPastFound = factory == skipPast;
501+
if (factory == skipPast) {
502+
skipPastFound = true;
502503
}
503504
continue;
504505
}
506+
505507
TypeAdapter<T> candidate = factory.create(this, type);
506508
if (candidate != null) {
507509
return candidate;
508510
}
509511
}
510-
throw new IllegalArgumentException("GSON cannot serialize or deserialize " + type);
512+
throw new IllegalArgumentException("GSON cannot serialize " + type);
511513
}
512514

513515
/**

gson/src/main/java/com/google/gson/internal/bind/JsonAdapterAnnotationTypeAdapterFactory.java

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616

1717
package com.google.gson.internal.bind;
1818

19-
import java.util.HashMap;
20-
import java.util.Map;
21-
2219
import com.google.gson.Gson;
2320
import com.google.gson.JsonDeserializer;
2421
import com.google.gson.JsonSerializer;
@@ -35,15 +32,6 @@
3532
* @since 2.3
3633
*/
3734
public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapterFactory {
38-
39-
@SuppressWarnings("rawtypes")
40-
private final ThreadLocal<Map<Class, TypeAdapterFactory>> activeJsonAdapterFactories = new ThreadLocal<Map<Class, TypeAdapterFactory>>() {
41-
@Override protected Map<Class, TypeAdapterFactory> initialValue() {
42-
// No need for a thread-safe map since we are using it in a single thread
43-
return new HashMap<Class, TypeAdapterFactory>();
44-
}
45-
};
46-
4735
private final ConstructorConstructor constructorConstructor;
4836

4937
public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
@@ -61,75 +49,34 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) {
6149
return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation);
6250
}
6351

64-
public <T> TypeAdapter<T> getDelegateAdapter(Gson gson, TypeAdapterFactory skipPast, TypeToken<T> targetType) {
65-
TypeAdapterFactory factory = getDelegateAdapterFactory(targetType);
66-
if (factory == skipPast) factory = null;
67-
return factory == null ? null: factory.create(gson, targetType);
68-
}
69-
70-
public <T> TypeAdapterFactory getDelegateAdapterFactory(TypeToken<T> targetType) {
71-
Class<?> annotatedClass = targetType.getRawType();
72-
JsonAdapter annotation = annotatedClass.getAnnotation(JsonAdapter.class);
73-
if (annotation == null) {
74-
return null;
75-
}
76-
return getTypeAdapterFactory(annotation, constructorConstructor);
77-
}
78-
7952
@SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals.
8053
TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson,
8154
TypeToken<?> type, JsonAdapter annotation) {
82-
Class<?> value = annotation.value();
83-
boolean isTypeAdapter = TypeAdapter.class.isAssignableFrom(value);
84-
boolean isJsonSerializer = JsonSerializer.class.isAssignableFrom(value);
85-
boolean isJsonDeserializer = JsonDeserializer.class.isAssignableFrom(value);
55+
Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct();
8656

8757
TypeAdapter<?> typeAdapter;
88-
if (isTypeAdapter || isJsonSerializer || isJsonDeserializer) {
89-
if (isTypeAdapter) {
90-
Class<TypeAdapter<?>> typeAdapterClass = (Class<TypeAdapter<?>>) value;
91-
typeAdapter = constructorConstructor.get(TypeToken.get(typeAdapterClass)).construct();
92-
} else if (isJsonSerializer || isJsonDeserializer) {
93-
JsonSerializer serializer = null;
94-
if (isJsonSerializer) {
95-
Class<JsonSerializer<?>> serializerClass = (Class<JsonSerializer<?>>) value;
96-
serializer = constructorConstructor.get(TypeToken.get(serializerClass)).construct();
97-
}
98-
JsonDeserializer deserializer = null;
99-
if (isJsonDeserializer) {
100-
Class<JsonDeserializer<?>> deserializerClass = (Class<JsonDeserializer<?>>) value;
101-
deserializer = constructorConstructor.get(TypeToken.get(deserializerClass)).construct();
102-
}
103-
typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
104-
} else {
105-
typeAdapter = null;
106-
}
107-
} else if (TypeAdapterFactory.class.isAssignableFrom(value)) {
108-
TypeAdapterFactory factory = getTypeAdapterFactory(annotation, constructorConstructor);
109-
typeAdapter = factory == null ? null : factory.create(gson, type);
58+
if (instance instanceof TypeAdapter) {
59+
typeAdapter = (TypeAdapter<?>) instance;
60+
} else if (instance instanceof TypeAdapterFactory) {
61+
typeAdapter = ((TypeAdapterFactory) instance).create(gson, type);
62+
} else if (instance instanceof JsonSerializer || instance instanceof JsonDeserializer) {
63+
JsonSerializer<?> serializer = instance instanceof JsonSerializer
64+
? (JsonSerializer) instance
65+
: null;
66+
JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer
67+
? (JsonDeserializer) instance
68+
: null;
69+
typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
11070
} else {
11171
throw new IllegalArgumentException(
112-
"@JsonAdapter value must be TypeAdapter, TypeAdapterFactory, JsonSerializer or JsonDeserializer reference.");
72+
"@JsonAdapter value must be TypeAdapter, TypeAdapterFactory, "
73+
+ "JsonSerializer or JsonDeserializer reference.");
11374
}
75+
11476
if (typeAdapter != null) {
11577
typeAdapter = typeAdapter.nullSafe();
11678
}
117-
return typeAdapter;
118-
}
11979

120-
121-
@SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals.
122-
TypeAdapterFactory getTypeAdapterFactory(JsonAdapter annotation, ConstructorConstructor constructorConstructor) {
123-
Class<?> value = annotation.value();
124-
if (!TypeAdapterFactory.class.isAssignableFrom(value)) return null;
125-
Map<Class, TypeAdapterFactory> adapterFactories = activeJsonAdapterFactories.get();
126-
TypeAdapterFactory factory = adapterFactories.get(value);
127-
if (factory == null) {
128-
Class<TypeAdapterFactory> typeAdapterFactoryClass = (Class<TypeAdapterFactory>) value;
129-
factory = constructorConstructor.get(TypeToken.get(typeAdapterFactoryClass))
130-
.construct();
131-
adapterFactories.put(value, factory);
132-
}
133-
return factory;
80+
return typeAdapter;
13481
}
13582
}

gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import com.google.gson.stream.JsonReader;
3333
import com.google.gson.stream.JsonToken;
3434
import com.google.gson.stream.JsonWriter;
35-
3635
import java.io.IOException;
3736
import java.lang.reflect.Field;
3837
import java.lang.reflect.Type;
@@ -110,7 +109,7 @@ private ReflectiveTypeAdapterFactory.BoundField createBoundField(
110109
TypeAdapter<?> mapped = null;
111110
if (annotation != null) {
112111
mapped = jsonAdapterFactory.getTypeAdapter(
113-
constructorConstructor, context, fieldType, annotation);
112+
constructorConstructor, context, fieldType, annotation);
114113
}
115114
final boolean jsonAdapterPresent = mapped != null;
116115
if (mapped == null) mapped = context.getAdapter(fieldType);

gson/src/test/java/com/google/gson/functional/JsonAdapterSerializerDeserializerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2008 Google Inc.
2+
* Copyright (C) 2016 Google Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)