Merge branch '6.2.x'

# Conflicts:
#	spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java
This commit is contained in:
Juergen Hoeller 2025-03-05 22:47:24 +01:00
commit a605f07100
4 changed files with 46 additions and 2 deletions

View File

@ -66,11 +66,15 @@ public class SimpleAutowireCandidateResolver implements AutowireCandidateResolve
* @see org.springframework.beans.factory.config.BeanDefinition#isAutowireCandidate()
* @see AbstractBeanDefinition#isDefaultCandidate()
*/
@SuppressWarnings("unchecked")
public static <T> Map<String, T> resolveAutowireCandidates(ConfigurableListableBeanFactory lbf, Class<T> type) {
Map<String, T> candidates = new LinkedHashMap<>();
for (String beanName : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(lbf, type)) {
if (AutowireUtils.isAutowireCandidate(lbf, beanName)) {
candidates.put(beanName, lbf.getBean(beanName, type));
Object beanInstance = lbf.getBean(beanName);
if (!(beanInstance instanceof NullBean)) {
candidates.put(beanName, (T) beanInstance);
}
}
}
return candidates;

View File

@ -1770,6 +1770,10 @@ class AutowiredAnnotationBeanPostProcessorTests {
parent.registerBeanDefinition("testBean4", tb4);
bf.setParentBeanFactory(parent);
RootBeanDefinition tb5 = new RootBeanDefinition(NullFactoryMethods.class);
tb5.setFactoryMethodName("createTestBean");
bf.registerBeanDefinition("testBean5", tb5);
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
assertThat(bean.streamTestBeans()).containsExactly(bf.getBean("testBean1", TestBean.class),
bf.getBean("testBean2", TestBean.class));
@ -1789,7 +1793,7 @@ class AutowiredAnnotationBeanPostProcessorTests {
Map<String, TestBean> typeMatches = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, TestBean.class);
assertThat(typeMatches.remove("testBean3")).isNotNull();
Map<String, TestBean> candidates = SimpleAutowireCandidateResolver.resolveAutowireCandidates(bf, TestBean.class);
assertThat(candidates).containsExactlyEntriesOf(candidates);
assertThat(candidates).containsExactlyEntriesOf(typeMatches);
}
@Test

View File

@ -341,6 +341,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
public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
@ -610,12 +617,20 @@ public class GenericConversionService implements ConfigurableConversionService {
}
public @Nullable 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;
}

View File

@ -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;
@ -969,4 +981,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));
}
}
}