Fix a regression I introduced with the changes to type hierarchy registration. If the registered type was a raw type, we need to also match the parameterizations of that type.

This commit is contained in:
Jesse Wilson 2011-11-23 13:38:25 +00:00
parent a069f4d883
commit 9a80d095d9
2 changed files with 36 additions and 36 deletions

View File

@ -70,11 +70,9 @@ public final class GsonBuilder {
private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY; private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
private final Map<Type, InstanceCreator<?>> instanceCreators private final Map<Type, InstanceCreator<?>> instanceCreators
= new HashMap<Type, InstanceCreator<?>>(); = new HashMap<Type, InstanceCreator<?>>();
private final List<TypeAdapter.Factory> factories private final List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
= new ArrayList<TypeAdapter.Factory>();
/** tree-style hierarchy factories. These come after factories for backwards compatibility. */ /** tree-style hierarchy factories. These come after factories for backwards compatibility. */
private final List<TypeAdapter.Factory> hierarchyFactories private final List<TypeAdapter.Factory> hierarchyFactories = new ArrayList<TypeAdapter.Factory>();
= new ArrayList<TypeAdapter.Factory>();
private boolean serializeNulls; private boolean serializeNulls;
private String datePattern; private String datePattern;
private int dateStyle = DateFormat.DEFAULT; private int dateStyle = DateFormat.DEFAULT;
@ -452,11 +450,11 @@ public final class GsonBuilder {
"Cannot register type adapters for " + type); "Cannot register type adapters for " + type);
} }
if (typeAdapter instanceof InstanceCreator<?>) { if (typeAdapter instanceof InstanceCreator<?>) {
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter); instanceCreators.put(type, (InstanceCreator) typeAdapter);
} }
if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) { if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
TypeToken<?> typeToken = TypeToken.get(type); TypeToken<?> typeToken = TypeToken.get(type);
factories.add(TreeTypeAdapter.newFactory(typeToken, typeAdapter)); factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
} }
if (typeAdapter instanceof TypeAdapter<?>) { if (typeAdapter instanceof TypeAdapter<?>) {
factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter)); factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
@ -475,37 +473,19 @@ public final class GsonBuilder {
return this; return this;
} }
/**
* Configures Gson to use a custom {@link InstanceCreator} for the specified type. If an instance
* creator was previously registered for the specified class, it is overwritten. Since this method
* takes a type instead of a Class object, it can be used to register a specific handler for a
* generic type corresponding to a raw type.
*
*
* @param typeOfT The Type definition for T
* @param instanceCreator the instance creator for T
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
*/
private <T> GsonBuilder registerInstanceCreator(Type typeOfT,
InstanceCreator<? extends T> instanceCreator) {
instanceCreators.put(typeOfT, instanceCreator);
return this;
}
/** /**
* Configures Gson for custom serialization or deserialization for an inheritance type hierarchy. * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
* This method combines the registration of an {@link InstanceCreator}, {@link JsonSerializer}, * This method combines the registration of a {@link JsonSerializer} and a {@link
* and a {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} * JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements both of
* implements all the required interfaces for custom serialization with Gson. * the required interfaces for custom serialization with Gson. If a serializer or deserializer was
* If an instance creator, serializer or deserializer was previously registered for the specified * previously registered for the specified type hierarchy, it is overwritten. If a serializer or
* type hierarchy, it is overwritten. If an instance creator, serializer or deserializer is * deserializer is registered for a specific type in the type hierarchy, it will be invoked
* registered for a specific type in the type hierarchy, it will be invoked instead of the one * instead of the one registered for the type hierarchy.
* registered for the type hierarchy.
* *
* @param baseType the class definition for the type adapter being registered for the base class * @param baseType the class definition for the type adapter being registered for the base class
* or interface * or interface
* @param typeAdapter This object must implement at least one of the {@link InstanceCreator}, * @param typeAdapter This object must implement at least one of {@link JsonSerializer} or {@link
* {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces. * JsonDeserializer} interfaces.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.7 * @since 1.7
*/ */

View File

@ -78,21 +78,40 @@ final class TreeTypeAdapter<T> extends TypeAdapter<T> {
: (delegate = gson.getNextAdapter(skipPast, typeToken)); : (delegate = gson.getNextAdapter(skipPast, typeToken));
} }
/**
* Returns a new factory that will match each type against {@code exactType}.
*/
public static Factory newFactory(TypeToken<?> exactType, Object typeAdapter) { public static Factory newFactory(TypeToken<?> exactType, Object typeAdapter) {
return new SingleTypeFactory(typeAdapter, exactType, null); return new SingleTypeFactory(typeAdapter, exactType, false, null);
} }
/**
* Returns a new factory that will match each type and its raw type against
* {@code exactType}.
*/
public static Factory newFactoryWithMatchRawType(TypeToken<?> exactType, Object typeAdapter) {
// only bother matching raw types if exact type is a raw type
boolean matchRawType = exactType.getType() == exactType.getRawType();
return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null);
}
/**
* Returns a new factory that will match each type's raw type for assignability
* to {@code hierarchyType}.
*/
public static Factory newTypeHierarchyFactory(Class<?> hierarchyType, Object typeAdapter) { public static Factory newTypeHierarchyFactory(Class<?> hierarchyType, Object typeAdapter) {
return new SingleTypeFactory(typeAdapter, null, hierarchyType); return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);
} }
private static class SingleTypeFactory implements TypeAdapter.Factory { private static class SingleTypeFactory implements TypeAdapter.Factory {
private final TypeToken<?> exactType; private final TypeToken<?> exactType;
private final boolean matchRawType;
private final Class<?> hierarchyType; private final Class<?> hierarchyType;
private final JsonSerializer<?> serializer; private final JsonSerializer<?> serializer;
private final JsonDeserializer<?> deserializer; private final JsonDeserializer<?> deserializer;
private SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, Class<?> hierarchyType) { private SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType,
Class<?> hierarchyType) {
serializer = typeAdapter instanceof JsonSerializer serializer = typeAdapter instanceof JsonSerializer
? (JsonSerializer) typeAdapter ? (JsonSerializer) typeAdapter
: null; : null;
@ -101,13 +120,14 @@ final class TreeTypeAdapter<T> extends TypeAdapter<T> {
: null; : null;
$Gson$Preconditions.checkArgument(serializer != null || deserializer != null); $Gson$Preconditions.checkArgument(serializer != null || deserializer != null);
this.exactType = exactType; this.exactType = exactType;
this.matchRawType = matchRawType;
this.hierarchyType = hierarchyType; this.hierarchyType = hierarchyType;
} }
@SuppressWarnings("unchecked") // guarded by typeToken.equals() call @SuppressWarnings("unchecked") // guarded by typeToken.equals() call
public <T> TypeAdapter<T> create(Gson context, TypeToken<T> type) { public <T> TypeAdapter<T> create(Gson context, TypeToken<T> type) {
boolean matches = exactType != null boolean matches = exactType != null
? exactType.equals(type) ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType()
: hierarchyType.isAssignableFrom(type.getRawType()); : hierarchyType.isAssignableFrom(type.getRawType());
return matches return matches
? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer, ? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer,