Browse Source

Add fallback to pre-6.2.3 behavior for unresolvable generics

Closes gh-34535
pull/34656/head
Juergen Hoeller 10 months ago
parent
commit
2472126475
  1. 15
      spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java
  2. 21
      spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java

15
spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java

@ -348,6 +348,13 @@ public class GenericConversionService implements ConfigurableConversionService { @@ -348,6 +348,13 @@ public class GenericConversionService implements ConfigurableConversionService {
conditionalConverter.matches(sourceType, targetType);
}
public boolean matchesFallback(TypeDescriptor sourceType, TypeDescriptor targetType) {
return (this.typeInfo.getTargetType() == targetType.getObjectType() &&
this.targetType.hasUnresolvableGenerics() &&
(!(this.converter instanceof ConditionalConverter conditionalConverter) ||
conditionalConverter.matches(sourceType, targetType)));
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
@ -622,12 +629,20 @@ public class GenericConversionService implements ConfigurableConversionService { @@ -622,12 +629,20 @@ public class GenericConversionService implements ConfigurableConversionService {
@Nullable
public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
// Look for proper match among all converters (taking full generics into account)
for (GenericConverter converter : this.converters) {
if (!(converter instanceof ConditionalGenericConverter genericConverter) ||
genericConverter.matches(sourceType, targetType)) {
return converter;
}
}
// Fallback to pre-6.2.3 behavior: accept Class match for unresolvable generics
for (GenericConverter converter : this.converters) {
if (converter instanceof ConverterAdapter converterAdapter &&
converterAdapter.matchesFallback(sourceType, targetType)) {
return converter;
}
}
return null;
}

21
spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java

@ -581,6 +581,18 @@ class GenericConversionServiceTests { @@ -581,6 +581,18 @@ class GenericConversionServiceTests {
assertThat(bList).allMatch(e -> e instanceof BRaw);
}
@Test
void stringToListOfMapConverterWithFallbackMatch() {
conversionService.addConverter(new StringToListOfMapConverter());
List<Map<String, Object>> result = (List<Map<String, Object>>) conversionService.convert("foo",
TypeDescriptor.valueOf(String.class),
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Map.class))
);
assertThat("foo").isEqualTo(result.get(0).get("bar"));
}
@ExampleAnnotation(active = true)
public String annotatedString;
@ -971,4 +983,13 @@ class GenericConversionServiceTests { @@ -971,4 +983,13 @@ class GenericConversionServiceTests {
}
}
private static class StringToListOfMapConverter implements Converter<String, List<? extends Map<String, ?>>> {
@Override
public List<? extends Map<String, ?>> convert(String source) {
return List.of(Map.of("bar", source));
}
}
}

Loading…
Cancel
Save