Skip to content

Commit 70bb785

Browse files
committed
Turn nested generic FactoryBean type into resolved Class for fallback match
See gh-29385
1 parent 69736af commit 70bb785

File tree

2 files changed

+47
-20
lines changed

2 files changed

+47
-20
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java

+5
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ protected boolean checkGenericTypeMatch(BeanDefinitionHolder bdHolder, Dependenc
110110
Class<?> typeToBeMatched = dependencyType.resolve();
111111
if (typeToBeMatched != null && !FactoryBean.class.isAssignableFrom(typeToBeMatched)) {
112112
targetType = targetType.getGeneric();
113+
if (descriptor.fallbackMatchAllowed()) {
114+
// Matching the Class-based type determination for FactoryBean
115+
// objects in the lazy-determination getType code path below.
116+
targetType = ResolvableType.forClass(targetType.resolve());
117+
}
113118
}
114119
}
115120
}

spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java

+42-20
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616

1717
package org.springframework.context.annotation;
1818

19-
import java.util.Collections;
2019
import java.util.Map;
21-
import java.util.Set;
2220
import java.util.regex.Pattern;
2321

2422
import org.junit.jupiter.api.Test;
@@ -400,44 +398,66 @@ void individualBeanWithFactoryBeanSupplierAndTargetType() {
400398
void individualBeanWithFactoryBeanTypeAsTargetType() {
401399
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
402400
RootBeanDefinition bd1 = new RootBeanDefinition();
403-
bd1.setBeanClass(SetFactoryBean.class);
404-
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(Set.class, String.class)));
401+
bd1.setBeanClass(GenericHolderFactoryBean.class);
402+
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, String.class)));
405403
bd1.setLazyInit(true);
406404
context.registerBeanDefinition("fb1", bd1);
407405
RootBeanDefinition bd2 = new RootBeanDefinition();
408406
bd2.setBeanClass(UntypedFactoryBean.class);
409-
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(Set.class, Integer.class)));
407+
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
410408
bd2.setLazyInit(true);
411409
context.registerBeanDefinition("fb2", bd2);
412410
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryBeanInjectionPoints.class));
413411
context.refresh();
414412

415-
assertThat(context.getType("&fb1")).isEqualTo(SetFactoryBean.class);
416-
assertThat(context.getType("fb1")).isEqualTo(Set.class);
413+
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
414+
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
417415
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
418-
assertThat(context.getBeanNamesForType(SetFactoryBean.class)).hasSize(1);
416+
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
419417
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryBean).isSameAs(context.getBean("&fb1"));
420418
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryResult).isSameAs(context.getBean("fb1"));
421419
}
422420

421+
@Test
422+
void individualBeanWithUnresolvedFactoryBeanTypeAsTargetType() {
423+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
424+
RootBeanDefinition bd1 = new RootBeanDefinition();
425+
bd1.setBeanClass(GenericHolderFactoryBean.class);
426+
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Object.class)));
427+
bd1.setLazyInit(true);
428+
context.registerBeanDefinition("fb1", bd1);
429+
RootBeanDefinition bd2 = new RootBeanDefinition();
430+
bd2.setBeanClass(UntypedFactoryBean.class);
431+
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
432+
bd2.setLazyInit(true);
433+
context.registerBeanDefinition("fb2", bd2);
434+
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
435+
context.refresh();
436+
437+
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
438+
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
439+
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
440+
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
441+
}
442+
423443
@Test
424444
void individualBeanWithFactoryBeanObjectTypeAsTargetType() {
425445
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
426446
RootBeanDefinition bd1 = new RootBeanDefinition();
427-
bd1.setBeanClass(SetFactoryBean.class);
428-
bd1.setTargetType(ResolvableType.forClassWithGenerics(Set.class, String.class));
447+
bd1.setBeanClass(GenericHolderFactoryBean.class);
448+
bd1.setTargetType(ResolvableType.forClassWithGenerics(GenericHolder.class, String.class));
429449
context.registerBeanDefinition("fb1", bd1);
430450
RootBeanDefinition bd2 = new RootBeanDefinition();
431451
bd2.setBeanClass(UntypedFactoryBean.class);
432-
bd2.setTargetType(ResolvableType.forClassWithGenerics(Set.class, Integer.class));
452+
bd2.setTargetType(ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class));
433453
context.registerBeanDefinition("fb2", bd2);
434454
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
435455
context.refresh();
436456

437-
assertThat(context.getType("&fb1")).isEqualTo(SetFactoryBean.class);
438-
assertThat(context.getType("fb1")).isEqualTo(Set.class);
457+
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
458+
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
439459
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
440-
assertThat(context.getBeanNamesForType(SetFactoryBean.class)).hasSize(1);
460+
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
441461
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
442462
}
443463

@@ -663,16 +683,18 @@ public boolean isSingleton() {
663683
}
664684
}
665685

666-
static class SetFactoryBean implements FactoryBean<Set<String>> {
686+
static class GenericHolder<T> {}
687+
688+
static class GenericHolderFactoryBean implements FactoryBean<GenericHolder<?>> {
667689

668690
@Override
669-
public Set<String> getObject() {
670-
return Collections.emptySet();
691+
public GenericHolder<?> getObject() {
692+
return new GenericHolder<>();
671693
}
672694

673695
@Override
674696
public Class<?> getObjectType() {
675-
return Set.class;
697+
return GenericHolder.class;
676698
}
677699

678700
@Override
@@ -684,13 +706,13 @@ public boolean isSingleton() {
684706
static class FactoryResultInjectionPoint {
685707

686708
@Autowired
687-
Set<String> factoryResult;
709+
GenericHolder<String> factoryResult;
688710
}
689711

690712
static class FactoryBeanInjectionPoints extends FactoryResultInjectionPoint {
691713

692714
@Autowired
693-
FactoryBean<Set<String>> factoryBean;
715+
FactoryBean<GenericHolder<String>> factoryBean;
694716
}
695717
}
696718

0 commit comments

Comments
 (0)