Turn nested generic FactoryBean type into resolved Class for fallback match
See gh-29385
This commit is contained in:
parent
69736af5fc
commit
70bb785ed6
|
@ -110,6 +110,11 @@ public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCan
|
||||||
Class<?> typeToBeMatched = dependencyType.resolve();
|
Class<?> typeToBeMatched = dependencyType.resolve();
|
||||||
if (typeToBeMatched != null && !FactoryBean.class.isAssignableFrom(typeToBeMatched)) {
|
if (typeToBeMatched != null && !FactoryBean.class.isAssignableFrom(typeToBeMatched)) {
|
||||||
targetType = targetType.getGeneric();
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.context.annotation;
|
package org.springframework.context.annotation;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -400,44 +398,66 @@ class AnnotationConfigApplicationContextTests {
|
||||||
void individualBeanWithFactoryBeanTypeAsTargetType() {
|
void individualBeanWithFactoryBeanTypeAsTargetType() {
|
||||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||||
RootBeanDefinition bd1 = new RootBeanDefinition();
|
RootBeanDefinition bd1 = new RootBeanDefinition();
|
||||||
bd1.setBeanClass(SetFactoryBean.class);
|
bd1.setBeanClass(GenericHolderFactoryBean.class);
|
||||||
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(Set.class, String.class)));
|
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, String.class)));
|
||||||
bd1.setLazyInit(true);
|
bd1.setLazyInit(true);
|
||||||
context.registerBeanDefinition("fb1", bd1);
|
context.registerBeanDefinition("fb1", bd1);
|
||||||
RootBeanDefinition bd2 = new RootBeanDefinition();
|
RootBeanDefinition bd2 = new RootBeanDefinition();
|
||||||
bd2.setBeanClass(UntypedFactoryBean.class);
|
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);
|
bd2.setLazyInit(true);
|
||||||
context.registerBeanDefinition("fb2", bd2);
|
context.registerBeanDefinition("fb2", bd2);
|
||||||
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryBeanInjectionPoints.class));
|
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryBeanInjectionPoints.class));
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
||||||
assertThat(context.getType("&fb1")).isEqualTo(SetFactoryBean.class);
|
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
|
||||||
assertThat(context.getType("fb1")).isEqualTo(Set.class);
|
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
|
||||||
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
|
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).factoryBean).isSameAs(context.getBean("&fb1"));
|
||||||
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryResult).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
|
@Test
|
||||||
void individualBeanWithFactoryBeanObjectTypeAsTargetType() {
|
void individualBeanWithFactoryBeanObjectTypeAsTargetType() {
|
||||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||||
RootBeanDefinition bd1 = new RootBeanDefinition();
|
RootBeanDefinition bd1 = new RootBeanDefinition();
|
||||||
bd1.setBeanClass(SetFactoryBean.class);
|
bd1.setBeanClass(GenericHolderFactoryBean.class);
|
||||||
bd1.setTargetType(ResolvableType.forClassWithGenerics(Set.class, String.class));
|
bd1.setTargetType(ResolvableType.forClassWithGenerics(GenericHolder.class, String.class));
|
||||||
context.registerBeanDefinition("fb1", bd1);
|
context.registerBeanDefinition("fb1", bd1);
|
||||||
RootBeanDefinition bd2 = new RootBeanDefinition();
|
RootBeanDefinition bd2 = new RootBeanDefinition();
|
||||||
bd2.setBeanClass(UntypedFactoryBean.class);
|
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("fb2", bd2);
|
||||||
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
|
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
||||||
assertThat(context.getType("&fb1")).isEqualTo(SetFactoryBean.class);
|
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
|
||||||
assertThat(context.getType("fb1")).isEqualTo(Set.class);
|
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
|
||||||
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
|
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"));
|
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,16 +683,18 @@ class AnnotationConfigApplicationContextTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SetFactoryBean implements FactoryBean<Set<String>> {
|
static class GenericHolder<T> {}
|
||||||
|
|
||||||
|
static class GenericHolderFactoryBean implements FactoryBean<GenericHolder<?>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getObject() {
|
public GenericHolder<?> getObject() {
|
||||||
return Collections.emptySet();
|
return new GenericHolder<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getObjectType() {
|
public Class<?> getObjectType() {
|
||||||
return Set.class;
|
return GenericHolder.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -684,13 +706,13 @@ class AnnotationConfigApplicationContextTests {
|
||||||
static class FactoryResultInjectionPoint {
|
static class FactoryResultInjectionPoint {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
Set<String> factoryResult;
|
GenericHolder<String> factoryResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class FactoryBeanInjectionPoints extends FactoryResultInjectionPoint {
|
static class FactoryBeanInjectionPoints extends FactoryResultInjectionPoint {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
FactoryBean<Set<String>> factoryBean;
|
FactoryBean<GenericHolder<String>> factoryBean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue