Skip to content

Commit 5c35930

Browse files
committed
Fix GenericConversionService selects incorrect converter
Signed-off-by: belljun3395 <[email protected]>
1 parent 551f6c0 commit 5c35930

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

Diff for: spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java

+44-4
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,50 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
342342
}
343343

344344
public boolean matchesFallback(TypeDescriptor sourceType, TypeDescriptor targetType) {
345-
return (this.typeInfo.getTargetType() == targetType.getObjectType() &&
346-
this.targetType.hasUnresolvableGenerics() &&
347-
(!(this.converter instanceof ConditionalConverter conditionalConverter) ||
348-
conditionalConverter.matches(sourceType, targetType)));
345+
if (this.typeInfo.getTargetType() != targetType.getObjectType()) {
346+
return false;
347+
}
348+
349+
if (!this.targetType.hasUnresolvableGenerics()) {
350+
return false;
351+
}
352+
353+
boolean assignable = isAssignableTo(targetType.getResolvableType());
354+
if (!assignable) {
355+
return false;
356+
}
357+
358+
return !(this.converter instanceof ConditionalConverter conditionalConverter) ||
359+
conditionalConverter.matches(sourceType, targetType);
360+
}
361+
362+
private boolean isAssignableTo(ResolvableType expected) {
363+
return isAssignable(this.targetType, expected);
364+
}
365+
366+
private boolean isAssignable(ResolvableType actual, ResolvableType expected) {
367+
Class<?> actualResolved = actual.resolve(Object.class);
368+
Class<?> expectedResolved = expected.resolve(Object.class);
369+
if (!expectedResolved.isAssignableFrom(actualResolved)) {
370+
return false;
371+
}
372+
373+
ResolvableType[] actualGenerics = actual.getGenerics();
374+
ResolvableType[] expectedGenerics = expected.getGenerics();
375+
376+
if (actualGenerics.length != expectedGenerics.length) {
377+
return false;
378+
}
379+
380+
for (int i = 0; i < actualGenerics.length; i++) {
381+
ResolvableType actualGeneric = actualGenerics[i];
382+
ResolvableType expectedGeneric = expectedGenerics[i];
383+
if (!isAssignable(actualGeneric, expectedGeneric)) {
384+
return false;
385+
}
386+
}
387+
388+
return true;
349389
}
350390

351391
@Override

Diff for: spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,19 @@ void stringToListOfMapConverterWithFallbackMatch() {
594594
assertThat("foo").isEqualTo(result.get(0).get("bar"));
595595
}
596596

597+
@Test
598+
@SuppressWarnings("unchecked")
599+
void stringToListOfString() {
600+
conversionService.addConverter(new StringToCollectionConverter(conversionService));
601+
conversionService.addConverter(new StringToListOfMapConverter());
602+
603+
List<String> result = (List<String>) conversionService.convert("foo,bar",
604+
TypeDescriptor.valueOf(String.class),
605+
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))
606+
);
607+
608+
assertThat(result.get(0)).isEqualTo("foo");
609+
}
597610

598611
@ExampleAnnotation(active = true)
599612
public String annotatedString;
@@ -990,5 +1003,4 @@ private static class StringToListOfMapConverter implements Converter<String, Lis
9901003
return List.of(Map.of("bar", source));
9911004
}
9921005
}
993-
9941006
}

0 commit comments

Comments
 (0)