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(UUID.class, UUUID_TYPE_ADAPTER);
|
||||||
map.register(Locale.class, LOCALE_TYPE_ADAPTER);
|
map.register(Locale.class, LOCALE_TYPE_ADAPTER);
|
||||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
||||||
map.registerForTypeHierarchy(Set.class, COLLECTION_TYPE_ADAPTER);
|
|
||||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
||||||
map.register(Date.class, DATE_TYPE_ADAPTER);
|
map.register(Date.class, DATE_TYPE_ADAPTER);
|
||||||
map.register(java.sql.Date.class, JAVA_SQL_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(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER));
|
||||||
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
|
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
|
||||||
map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_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.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
|
||||||
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
|
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
|
||||||
map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_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() {
|
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() {
|
||||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
||||||
new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||||
map.register(Map.class, MAP_TYPE_ADAPTER);
|
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
||||||
|
|
||||||
// Add Collection type instance creators
|
// Add Collection type instance creators
|
||||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
||||||
|
|
||||||
map.register(Set.class, HASH_SET_CREATOR);
|
map.registerForTypeHierarchy(Set.class, HASH_SET_CREATOR);
|
||||||
map.register(SortedSet.class, TREE_SET_CREATOR);
|
map.registerForTypeHierarchy(SortedSet.class, TREE_SET_CREATOR);
|
||||||
map.register(TreeSet.class, TREE_SET_CREATOR);
|
|
||||||
map.register(Properties.class, PROPERTIES_CREATOR);
|
map.register(Properties.class, PROPERTIES_CREATOR);
|
||||||
map.makeUnmodifiable();
|
map.makeUnmodifiable();
|
||||||
return map;
|
return map;
|
||||||
|
@ -54,4 +54,9 @@ final class Pair<FIRST, SECOND> {
|
|||||||
private static boolean equal(Object a, Object b) {
|
private static boolean equal(Object a, Object b) {
|
||||||
return a == b || (a != null && a.equals(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);
|
logger.log(Level.WARNING, "Overriding the existing type handler for {0}", pair.first);
|
||||||
typeHierarchyList.remove(index);
|
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
|
// We want stack behavior for adding to this list. A type adapter added subsequently should
|
||||||
// override a previously registered one.
|
// override a previously registered one.
|
||||||
typeHierarchyList.add(0, pair);
|
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) {
|
public synchronized void register(Type typeOfT, T value) {
|
||||||
if (!modifiable) {
|
if (!modifiable) {
|
||||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||||
@ -78,7 +94,10 @@ final class ParameterizedTypeHandlerMap<T> {
|
|||||||
register(entry.getKey(), entry.getValue());
|
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);
|
int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
registerForTypeHierarchy(entry);
|
registerForTypeHierarchy(entry);
|
||||||
|
@ -109,6 +109,21 @@ public class ParameterizedTypeHandlerMapTest extends TestCase {
|
|||||||
assertEquals("baseHandler", handler);
|
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 {
|
private static class SubOfSub extends Sub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user