Unwrap nested generic type within FactoryBean target type if necessary

Closes gh-29385
This commit is contained in:
Juergen Hoeller
2022-11-08 20:22:12 +01:00
parent f26a7dee97
commit 0e9eab55ce
2 changed files with 85 additions and 12 deletions

View File

@@ -16,7 +16,9 @@
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;
@@ -372,8 +374,8 @@ class AnnotationConfigApplicationContextTests {
context.registerBean("fb", NonInstantiatedFactoryBean.class, NonInstantiatedFactoryBean::new, bd -> bd.setLazyInit(true));
context.refresh();
assertThat(context.getType("fb")).isEqualTo(String.class);
assertThat(context.getType("&fb")).isEqualTo(NonInstantiatedFactoryBean.class);
assertThat(context.getType("fb")).isEqualTo(String.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(1);
assertThat(context.getBeanNamesForType(NonInstantiatedFactoryBean.class)).hasSize(1);
}
@@ -388,25 +390,55 @@ class AnnotationConfigApplicationContextTests {
context.registerBeanDefinition("fb", bd);
context.refresh();
assertThat(context.getType("fb")).isEqualTo(String.class);
assertThat(context.getType("&fb")).isEqualTo(FactoryBean.class);
assertThat(context.getType("fb")).isEqualTo(String.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(1);
assertThat(context.getBeanNamesForType(NonInstantiatedFactoryBean.class)).isEmpty();
}
@Test
void individualBeanWithFactoryBeanObjectTypeAsTargetType() {
void individualBeanWithFactoryBeanTypeAsTargetType() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
RootBeanDefinition bd = new RootBeanDefinition();
bd.setBeanClass(TypedFactoryBean.class);
bd.setTargetType(String.class);
context.registerBeanDefinition("fb", bd);
RootBeanDefinition bd1 = new RootBeanDefinition();
bd1.setBeanClass(SetFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(Set.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.setLazyInit(true);
context.registerBeanDefinition("fb2", bd2);
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryBeanInjectionPoints.class));
context.refresh();
assertThat(context.getType("&fb")).isEqualTo(TypedFactoryBean.class);
assertThat(context.getType("fb")).isEqualTo(String.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(1);
assertThat(context.getBeanNamesForType(TypedFactoryBean.class)).hasSize(1);
assertThat(context.getType("&fb1")).isEqualTo(SetFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(Set.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBeanNamesForType(SetFactoryBean.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 individualBeanWithFactoryBeanObjectTypeAsTargetType() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
RootBeanDefinition bd1 = new RootBeanDefinition();
bd1.setBeanClass(SetFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(Set.class, String.class));
context.registerBeanDefinition("fb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition();
bd2.setBeanClass(UntypedFactoryBean.class);
bd2.setTargetType(ResolvableType.forClassWithGenerics(Set.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.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBeanNamesForType(SetFactoryBean.class)).hasSize(1);
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
}
@Test
@@ -630,6 +662,36 @@ class AnnotationConfigApplicationContextTests {
return false;
}
}
static class SetFactoryBean implements FactoryBean<Set<String>> {
@Override
public Set<String> getObject() {
return Collections.emptySet();
}
@Override
public Class<?> getObjectType() {
return Set.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
static class FactoryResultInjectionPoint {
@Autowired
Set<String> factoryResult;
}
static class FactoryBeanInjectionPoints extends FactoryResultInjectionPoint {
@Autowired
FactoryBean<Set<String>> factoryBean;
}
}
class TestBean {