Skip to content

Commit 8d2a346

Browse files
nexx512odrotbohm
authored andcommitted
Fixed resolving generic types for Vavr maps.
Issue #2517.
1 parent 8ebe52d commit 8d2a346

File tree

4 files changed

+64
-8
lines changed

4 files changed

+64
-8
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* @author Oliver Gierke
4040
* @author Mark Paluch
4141
* @author Christoph Strobl
42+
* @author Jürgen Diez
4243
*/
4344
class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
4445

@@ -63,7 +64,7 @@ public ParameterizedTypeInformation(ParameterizedType type, TypeDiscoverer<?> pa
6364
@Nullable
6465
protected TypeInformation<?> doGetMapValueType() {
6566

66-
if (Map.class.isAssignableFrom(getType())) {
67+
if (isMap()) {
6768

6869
var arguments = type.getActualTypeArguments();
6970

@@ -141,13 +142,13 @@ public boolean isAssignableFrom(TypeInformation<?> target) {
141142
@Nullable
142143
protected TypeInformation<?> doGetComponentType() {
143144

144-
var isCustomMapImplementation = isMap() && !getType().equals(Map.class);
145+
var isCustomMapImplementation = isMap() && !isMapBaseType();
145146

146147
if (isCustomMapImplementation) {
147-
return getRequiredSuperTypeInformation(Map.class).getComponentType();
148+
return getRequiredSuperTypeInformation(getMapBaseType()).getComponentType();
148149
}
149150

150-
return createInfo(type.getActualTypeArguments()[0]);
151+
return createInfo(this.type.getActualTypeArguments()[0]);
151152
}
152153

153154
@Override

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
*/
4646
class TypeDiscoverer<S> implements TypeInformation<S> {
4747

48-
private static final Class<?>[] MAP_TYPES;
48+
protected static final Class<?>[] MAP_TYPES;
4949
private static final Class<?>[] COLLECTION_TYPES;
5050

5151
static {
@@ -328,7 +328,7 @@ public TypeInformation<?> getMapValueType() {
328328

329329
@Nullable
330330
protected TypeInformation<?> doGetMapValueType() {
331-
return isMap() ? getTypeArgument(getBaseType(MAP_TYPES), 1)
331+
return isMap() ? getTypeArgument(getMapBaseType(), 1)
332332
: getTypeArguments().stream().skip(1).findFirst().orElse(null);
333333
}
334334

@@ -357,7 +357,7 @@ protected TypeInformation<?> doGetComponentType() {
357357
}
358358

359359
if (isMap()) {
360-
return getTypeArgument(getBaseType(MAP_TYPES), 0);
360+
return getTypeArgument(getMapBaseType(), 0);
361361
}
362362

363363
if (Iterable.class.isAssignableFrom(rawType)) {
@@ -469,6 +469,27 @@ private TypeInformation<?> getTypeArgument(Class<?> bound, int index) {
469469
: null;
470470
}
471471

472+
protected boolean isMapBaseType() {
473+
return isBaseType(MAP_TYPES);
474+
}
475+
476+
private boolean isBaseType(Class<?>[] candidates) {
477+
478+
Class<S> type = getType();
479+
480+
for (Class<?> candidate: candidates) {
481+
if (candidate.equals(type)) {
482+
return true;
483+
}
484+
}
485+
486+
return false;
487+
}
488+
489+
protected Class<?> getMapBaseType() {
490+
return getBaseType(MAP_TYPES);
491+
}
492+
472493
private Class<?> getBaseType(Class<?>[] candidates) {
473494

474495
var type = getType();

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*
4141
* @author Oliver Gierke
4242
* @author Mark Paluch
43+
* @author Jürgen Diez
4344
*/
4445
@ExtendWith(MockitoExtension.class)
4546
@MockitoSettings(strictness = Strictness.LENIENT)
@@ -76,22 +77,39 @@ void considersTypeInformationsWithSameParentsNotEqual() {
7677
}
7778

7879
@Test // DATACMNS-88
79-
void resolvesMapValueTypeCorrectly() {
80+
void resolvesMapTypesCorrectly() {
8081

8182
TypeInformation<Foo> type = ClassTypeInformation.from(Foo.class);
8283
var propertyType = type.getProperty("param");
8384
var value = propertyType.getProperty("value");
8485

86+
assertThat(propertyType.getComponentType().getType()).isEqualTo(Locale.class);
8587
assertThat(value.getType()).isEqualTo(String.class);
8688
assertThat(propertyType.getMapValueType().getType()).isEqualTo(String.class);
8789

8890
propertyType = type.getProperty("param2");
8991
value = propertyType.getProperty("value");
9092

93+
assertThat(propertyType.getComponentType().getType()).isEqualTo(String.class);
9194
assertThat(value.getType()).isEqualTo(String.class);
9295
assertThat(propertyType.getMapValueType().getType()).isEqualTo(Locale.class);
9396
}
9497

98+
@Test
99+
void resolvesVavrMapTypesCorrectly() {
100+
101+
TypeInformation<VavrFoo> type = ClassTypeInformation.from(VavrFoo.class);
102+
TypeInformation<?> propertyType = type.getProperty("param");
103+
104+
assertThat(propertyType.getComponentType().getType()).isEqualTo(Locale.class);
105+
assertThat(propertyType.getMapValueType().getType()).isEqualTo(String.class);
106+
107+
propertyType = type.getProperty("param2");
108+
109+
assertThat(propertyType.getComponentType().getType()).isEqualTo(String.class);
110+
assertThat(propertyType.getMapValueType().getType()).isEqualTo(Locale.class);
111+
}
112+
95113
@Test // DATACMNS-446
96114
void createsToStringRepresentation() {
97115

@@ -170,6 +188,11 @@ class Foo {
170188
Localized2<String> param2;
171189
}
172190

191+
class VavrFoo {
192+
io.vavr.collection.HashMap<Locale, String> param;
193+
io.vavr.collection.HashMap<String, Locale> param2;
194+
}
195+
173196
class Bar {
174197
List<String> param;
175198
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,15 @@ void considerVavrMapToBeAMap() {
187187
assertThat(type.isMap()).isTrue();
188188
}
189189

190+
@Test // #2517
191+
void returnsComponentAndValueTypesForVavrMapExtensions() {
192+
193+
var discoverer = new TypeDiscoverer<>(CustomVavrMap.class, EMPTY_MAP);
194+
195+
assertThat(discoverer.getMapValueType().getType()).isEqualTo(Locale.class);
196+
assertThat(discoverer.getComponentType().getType()).isEqualTo(String.class);
197+
}
198+
190199
@Test // #2511
191200
void considerVavrSetToBeCollectionLike() {
192201

@@ -260,4 +269,6 @@ public Iterator<String> iterator() {
260269
return Collections.emptyIterator();
261270
}
262271
}
272+
273+
interface CustomVavrMap extends io.vavr.collection.Map<String, Locale> {}
263274
}

0 commit comments

Comments
 (0)