diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index a3cf3d79..e6533e4d 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -70,11 +70,9 @@ public final class GsonBuilder { private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY; private final Map> instanceCreators = new HashMap>(); - private final List factories - = new ArrayList(); + private final List factories = new ArrayList(); /** tree-style hierarchy factories. These come after factories for backwards compatibility. */ - private final List hierarchyFactories - = new ArrayList(); + private final List hierarchyFactories = new ArrayList(); private boolean serializeNulls; private String datePattern; private int dateStyle = DateFormat.DEFAULT; @@ -452,11 +450,11 @@ public final class GsonBuilder { "Cannot register type adapters for " + type); } if (typeAdapter instanceof InstanceCreator) { - registerInstanceCreator(type, (InstanceCreator) typeAdapter); + instanceCreators.put(type, (InstanceCreator) typeAdapter); } if (typeAdapter instanceof JsonSerializer || typeAdapter instanceof JsonDeserializer) { TypeToken typeToken = TypeToken.get(type); - factories.add(TreeTypeAdapter.newFactory(typeToken, typeAdapter)); + factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter)); } if (typeAdapter instanceof TypeAdapter) { factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter)); @@ -475,37 +473,19 @@ public final class GsonBuilder { 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 GsonBuilder registerInstanceCreator(Type typeOfT, - InstanceCreator instanceCreator) { - instanceCreators.put(typeOfT, instanceCreator); - return this; - } - /** * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy. - * This method combines the registration of an {@link InstanceCreator}, {@link JsonSerializer}, - * and a {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} - * implements all the required interfaces for custom serialization with Gson. - * If an instance creator, serializer or deserializer was previously registered for the specified - * type hierarchy, it is overwritten. If an instance creator, serializer or deserializer is - * registered for a specific type in the type hierarchy, it will be invoked instead of the one - * registered for the type hierarchy. + * This method combines the registration of a {@link JsonSerializer} and a {@link + * JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements both of + * the required interfaces for custom serialization with Gson. If a serializer or deserializer was + * previously registered for the specified type hierarchy, it is overwritten. If a serializer or + * deserializer is registered for a specific type in the type hierarchy, it will be invoked + * instead of the one registered for the type hierarchy. * * @param baseType the class definition for the type adapter being registered for the base class * or interface - * @param typeAdapter This object must implement at least one of the {@link InstanceCreator}, - * {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces. + * @param typeAdapter This object must implement at least one of {@link JsonSerializer} or {@link + * JsonDeserializer} interfaces. * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.7 */ diff --git a/gson/src/main/java/com/google/gson/TreeTypeAdapter.java b/gson/src/main/java/com/google/gson/TreeTypeAdapter.java index 0f895dec..36eb9afd 100644 --- a/gson/src/main/java/com/google/gson/TreeTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/TreeTypeAdapter.java @@ -78,21 +78,40 @@ final class TreeTypeAdapter extends TypeAdapter { : (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) { - 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) { - return new SingleTypeFactory(typeAdapter, null, hierarchyType); + return new SingleTypeFactory(typeAdapter, null, false, hierarchyType); } private static class SingleTypeFactory implements TypeAdapter.Factory { private final TypeToken exactType; + private final boolean matchRawType; private final Class hierarchyType; private final JsonSerializer serializer; 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 ? (JsonSerializer) typeAdapter : null; @@ -101,13 +120,14 @@ final class TreeTypeAdapter extends TypeAdapter { : null; $Gson$Preconditions.checkArgument(serializer != null || deserializer != null); this.exactType = exactType; + this.matchRawType = matchRawType; this.hierarchyType = hierarchyType; } @SuppressWarnings("unchecked") // guarded by typeToken.equals() call public TypeAdapter create(Gson context, TypeToken type) { boolean matches = exactType != null - ? exactType.equals(type) + ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType() : hierarchyType.isAssignableFrom(type.getRawType()); return matches ? new TreeTypeAdapter((JsonSerializer) serializer,