Skip to content

Commit 50026d4

Browse files
committed
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<T> {} class Nested extends GenericType<String> {} class Concrete extends GenericType<Nested> {} 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.
1 parent ed290da commit 50026d4

File tree

2 files changed

+28
-2
lines changed

2 files changed

+28
-2
lines changed

src/main/java/org/springframework/data/util/ClassTypeInformation.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,12 @@ private static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> type, Coll
133133
map.put(entry.getKey(), entry.getValue());
134134

135135
if (value instanceof Class) {
136-
map.putAll(getTypeVariableMap((Class<?>) value, visited));
136+
137+
for (Entry<TypeVariable<?>, Type> nestedEntry : getTypeVariableMap((Class<?>) value, visited).entrySet()) {
138+
if (!map.containsKey(nestedEntry.getKey())) {
139+
map.put(nestedEntry.getKey(), nestedEntry.getValue());
140+
}
141+
}
137142
}
138143
}
139144

src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public void discoversArraysAndCollections() {
106106

107107
property = information.getProperty("rawSet");
108108
assertEquals(Set.class, property.getType());
109-
assertThat(property.getComponentType().getType(), is(Matchers.<Class<?>> equalTo(Object.class)));
109+
assertThat(property.getComponentType().getType(), is(Matchers.<Class<?>>equalTo(Object.class)));
110110
assertNull(property.getMapValueType());
111111
}
112112

@@ -402,6 +402,17 @@ public void specializedTypeEqualsAndHashCode() {
402402
assertThat(left.hashCode(), is(right.hashCode()));
403403
}
404404

405+
/**
406+
* @see DATACMNS-896
407+
*/
408+
@Test
409+
public void prefersLocalTypeMappingOverNestedWithSameGenericType() {
410+
411+
ClassTypeInformation<Concrete> information = ClassTypeInformation.from(Concrete.class);
412+
413+
assertThat(information.getProperty("field").getType(), is(typeCompatibleWith(Nested.class)));
414+
}
415+
405416
static class StringMapContainer extends MapContainer<String> {
406417

407418
}
@@ -590,4 +601,14 @@ static class Bar<T, S> extends AbstractBar<T, S> {
590601
T field;
591602
S anotherField;
592603
}
604+
605+
// DATACMNS-896
606+
607+
static class SomeType<T> {
608+
T field;
609+
}
610+
611+
static class Nested extends SomeType<String> {}
612+
613+
static class Concrete extends SomeType<Nested> {}
593614
}

0 commit comments

Comments
 (0)