Added checks to ensure that typeHierarchyAdapter being registered doesn't hide a previously existing one.
Fixed a bug where registerIfAbsent was adding type adapters in the reverse order of priority. Added toString() to Pair.
This commit is contained in:
parent
8aedbc84db
commit
b2af57d288
@ -110,7 +110,6 @@ final class DefaultTypeAdapters {
|
||||
map.register(UUID.class, UUUID_TYPE_ADAPTER);
|
||||
map.register(Locale.class, LOCALE_TYPE_ADAPTER);
|
||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
||||
map.registerForTypeHierarchy(Set.class, COLLECTION_TYPE_ADAPTER);
|
||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
||||
map.register(Date.class, DATE_TYPE_ADAPTER);
|
||||
map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER);
|
||||
@ -148,7 +147,6 @@ final class DefaultTypeAdapters {
|
||||
map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER));
|
||||
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
|
||||
map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER));
|
||||
map.registerForTypeHierarchy(Set.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER));
|
||||
map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
|
||||
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
|
||||
map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER));
|
||||
@ -186,14 +184,13 @@ final class DefaultTypeAdapters {
|
||||
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() {
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
||||
new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||
map.register(Map.class, MAP_TYPE_ADAPTER);
|
||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
||||
|
||||
// Add Collection type instance creators
|
||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
||||
|
||||
map.register(Set.class, HASH_SET_CREATOR);
|
||||
map.register(SortedSet.class, TREE_SET_CREATOR);
|
||||
map.register(TreeSet.class, TREE_SET_CREATOR);
|
||||
map.registerForTypeHierarchy(Set.class, HASH_SET_CREATOR);
|
||||
map.registerForTypeHierarchy(SortedSet.class, TREE_SET_CREATOR);
|
||||
map.register(Properties.class, PROPERTIES_CREATOR);
|
||||
map.makeUnmodifiable();
|
||||
return map;
|
||||
|
@ -54,4 +54,9 @@ final class Pair<FIRST, SECOND> {
|
||||
private static boolean equal(Object a, Object b) {
|
||||
return a == b || (a != null && a.equals(b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{%s,%s}", first, second);
|
||||
}
|
||||
}
|
@ -54,11 +54,27 @@ final class ParameterizedTypeHandlerMap<T> {
|
||||
logger.log(Level.WARNING, "Overriding the existing type handler for {0}", pair.first);
|
||||
typeHierarchyList.remove(index);
|
||||
}
|
||||
index = getIndexOfAnOverriddenHandler(pair.first);
|
||||
if (index >= 0) {
|
||||
throw new IllegalArgumentException("The specified type handler for type " + pair.first
|
||||
+ " hides the previously registered type hierarchy handler for "
|
||||
+ typeHierarchyList.get(index).first + ". Gson does not allow this.");
|
||||
}
|
||||
// We want stack behavior for adding to this list. A type adapter added subsequently should
|
||||
// override a previously registered one.
|
||||
typeHierarchyList.add(0, pair);
|
||||
}
|
||||
|
||||
private int getIndexOfAnOverriddenHandler(Class<?> type) {
|
||||
for (int i = typeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = typeHierarchyList.get(i);
|
||||
if (type.isAssignableFrom(entry.first)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized void register(Type typeOfT, T value) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
@ -78,7 +94,10 @@ final class ParameterizedTypeHandlerMap<T> {
|
||||
register(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
for (Pair<Class<?>, T> entry : other.typeHierarchyList) {
|
||||
// Quite important to traverse the typeHierarchyList from stack bottom first since
|
||||
// we want to register the handlers in the same order to preserve priority order
|
||||
for (int i = other.typeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = other.typeHierarchyList.get(i);
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first);
|
||||
if (index < 0) {
|
||||
registerForTypeHierarchy(entry);
|
||||
|
@ -109,6 +109,21 @@ public class ParameterizedTypeHandlerMapTest extends TestCase {
|
||||
assertEquals("baseHandler", handler);
|
||||
}
|
||||
|
||||
public void testReplaceExistingTypeHierarchyHandler() {
|
||||
paramMap.registerForTypeHierarchy(Base.class, "baseHandler");
|
||||
paramMap.registerForTypeHierarchy(Base.class, "base2Handler");
|
||||
String handler = paramMap.getHandlerFor(Base.class);
|
||||
assertEquals("base2Handler", handler);
|
||||
}
|
||||
|
||||
public void testHidingExistingTypeHierarchyHandlerIsDisallowed() {
|
||||
paramMap.registerForTypeHierarchy(Sub.class, "subHandler");
|
||||
try {
|
||||
paramMap.registerForTypeHierarchy(Base.class, "baseHandler");
|
||||
fail("A handler that hides an existing type hierarchy handler is not allowed");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
private static class SubOfSub extends Sub {
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user