Browse Source

Turn nested generic FactoryBean type into resolved Class for fallback match

See gh-29385
pull/29461/head
Juergen Hoeller 2 years ago
parent
commit
70bb785ed6
  1. 5
      spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
  2. 62
      spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java

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

@ -110,6 +110,11 @@ public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCan @@ -110,6 +110,11 @@ public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCan
Class<?> typeToBeMatched = dependencyType.resolve();
if (typeToBeMatched != null && !FactoryBean.class.isAssignableFrom(typeToBeMatched)) {
targetType = targetType.getGeneric();
if (descriptor.fallbackMatchAllowed()) {
// Matching the Class-based type determination for FactoryBean
// objects in the lazy-determination getType code path below.
targetType = ResolvableType.forClass(targetType.resolve());
}
}
}
}

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

@ -16,9 +16,7 @@ @@ -16,9 +16,7 @@
package org.springframework.context.annotation;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.junit.jupiter.api.Test;
@ -400,44 +398,66 @@ class AnnotationConfigApplicationContextTests { @@ -400,44 +398,66 @@ class AnnotationConfigApplicationContextTests {
void individualBeanWithFactoryBeanTypeAsTargetType() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
RootBeanDefinition bd1 = new RootBeanDefinition();
bd1.setBeanClass(SetFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(Set.class, String.class)));
bd1.setBeanClass(GenericHolderFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, String.class)));
bd1.setLazyInit(true);
context.registerBeanDefinition("fb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition();
bd2.setBeanClass(UntypedFactoryBean.class);
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(Set.class, Integer.class)));
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
bd2.setLazyInit(true);
context.registerBeanDefinition("fb2", bd2);
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryBeanInjectionPoints.class));
context.refresh();
assertThat(context.getType("&fb1")).isEqualTo(SetFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(Set.class);
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBeanNamesForType(SetFactoryBean.class)).hasSize(1);
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryBean).isSameAs(context.getBean("&fb1"));
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryResult).isSameAs(context.getBean("fb1"));
}
@Test
void individualBeanWithUnresolvedFactoryBeanTypeAsTargetType() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
RootBeanDefinition bd1 = new RootBeanDefinition();
bd1.setBeanClass(GenericHolderFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Object.class)));
bd1.setLazyInit(true);
context.registerBeanDefinition("fb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition();
bd2.setBeanClass(UntypedFactoryBean.class);
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
bd2.setLazyInit(true);
context.registerBeanDefinition("fb2", bd2);
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
context.refresh();
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
}
@Test
void individualBeanWithFactoryBeanObjectTypeAsTargetType() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
RootBeanDefinition bd1 = new RootBeanDefinition();
bd1.setBeanClass(SetFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(Set.class, String.class));
bd1.setBeanClass(GenericHolderFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(GenericHolder.class, String.class));
context.registerBeanDefinition("fb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition();
bd2.setBeanClass(UntypedFactoryBean.class);
bd2.setTargetType(ResolvableType.forClassWithGenerics(Set.class, Integer.class));
bd2.setTargetType(ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class));
context.registerBeanDefinition("fb2", bd2);
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
context.refresh();
assertThat(context.getType("&fb1")).isEqualTo(SetFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(Set.class);
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBeanNamesForType(SetFactoryBean.class)).hasSize(1);
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
}
@ -663,16 +683,18 @@ class AnnotationConfigApplicationContextTests { @@ -663,16 +683,18 @@ class AnnotationConfigApplicationContextTests {
}
}
static class SetFactoryBean implements FactoryBean<Set<String>> {
static class GenericHolder<T> {}
static class GenericHolderFactoryBean implements FactoryBean<GenericHolder<?>> {
@Override
public Set<String> getObject() {
return Collections.emptySet();
public GenericHolder<?> getObject() {
return new GenericHolder<>();
}
@Override
public Class<?> getObjectType() {
return Set.class;
return GenericHolder.class;
}
@Override
@ -684,13 +706,13 @@ class AnnotationConfigApplicationContextTests { @@ -684,13 +706,13 @@ class AnnotationConfigApplicationContextTests {
static class FactoryResultInjectionPoint {
@Autowired
Set<String> factoryResult;
GenericHolder<String> factoryResult;
}
static class FactoryBeanInjectionPoints extends FactoryResultInjectionPoint {
@Autowired
FactoryBean<Set<String>> factoryBean;
FactoryBean<GenericHolder<String>> factoryBean;
}
}

Loading…
Cancel
Save