From 4fa84fc983eb891a5c75938ce113c0e40dcf31a0 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sat, 20 Aug 2016 19:49:18 +0200 Subject: [PATCH] DATACMNS-896 - Improved detection of type variable mappings in recursively nested generics. If the same generic type was used on recursively nested generics declarations, like this: class GenericType {} class Nested extends GenericType {} class Concrete extends GenericType {} our traversal of the generics discovered T bound to String in Nested and as that is extending GenericType as well, the T detected here is the same instance as the T within the map discovered for Concrete. As we previously added the nested types after we added the original entry, the nested discovery overwrote the more local one. We now make sure the detected nested type variable mappings don't overwrite already existing ones. --- .../data/util/ClassTypeInformation.java | 7 +++++- .../util/ClassTypeInformationUnitTests.java | 23 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/springframework/data/util/ClassTypeInformation.java b/src/main/java/org/springframework/data/util/ClassTypeInformation.java index ee288dd10..a5b160455 100644 --- a/src/main/java/org/springframework/data/util/ClassTypeInformation.java +++ b/src/main/java/org/springframework/data/util/ClassTypeInformation.java @@ -133,7 +133,12 @@ public class ClassTypeInformation extends TypeDiscoverer { map.put(entry.getKey(), entry.getValue()); if (value instanceof Class) { - map.putAll(getTypeVariableMap((Class) value, visited)); + + for (Entry, Type> nestedEntry : getTypeVariableMap((Class) value, visited).entrySet()) { + if (!map.containsKey(nestedEntry.getKey())) { + map.put(nestedEntry.getKey(), nestedEntry.getValue()); + } + } } } diff --git a/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java b/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java index 5f9e42b5f..c4a4af0fa 100644 --- a/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java +++ b/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java @@ -106,7 +106,7 @@ public class ClassTypeInformationUnitTests { property = information.getProperty("rawSet"); assertEquals(Set.class, property.getType()); - assertThat(property.getComponentType().getType(), is(Matchers.> equalTo(Object.class))); + assertThat(property.getComponentType().getType(), is(Matchers.>equalTo(Object.class))); assertNull(property.getMapValueType()); } @@ -402,6 +402,17 @@ public class ClassTypeInformationUnitTests { assertThat(left.hashCode(), is(right.hashCode())); } + /** + * @see DATACMNS-896 + */ + @Test + public void prefersLocalTypeMappingOverNestedWithSameGenericType() { + + ClassTypeInformation information = ClassTypeInformation.from(Concrete.class); + + assertThat(information.getProperty("field").getType(), is(typeCompatibleWith(Nested.class))); + } + static class StringMapContainer extends MapContainer { } @@ -590,4 +601,14 @@ public class ClassTypeInformationUnitTests { T field; S anotherField; } + + // DATACMNS-896 + + static class SomeType { + T field; + } + + static class Nested extends SomeType {} + + static class Concrete extends SomeType {} }