Here is an example test case:
import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ResolvableType;
import static org.junit.Assert.assertTrue;
public class FactoryTests {
@Test
public void testAutowire() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
TestConfig.class);
ClassWithGenericBar classWithGenericBar = context.getBean(ClassWithGenericBar.class);
assertTrue(classWithGenericBar.stringGenericBar.type.equals(String.class));
}
@Test
public void testGetByType() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
TestConfig.class);
String[] names = context.getBeanNamesForType(ResolvableType.forClassWithGenerics(GenericBar.class, String.class));
assertTrue(names.length > 0);
}
static class TestConfig {
@Bean
GenericBarFactory<String> stringGenericBarFactory() {
return new GenericBarFactory<>(String.class);
}
@Bean
GenericBarFactory<Integer> integerGenericBarFactory() {
return new GenericBarFactory<>(Integer.class);
}
@Bean
ClassWithGenericBar classWithGenericBar() {
return new ClassWithGenericBar();
}
}
public static class GenericBar<T> {
Class<T> type;
public GenericBar(Class<T> type) {
this.type = type;
}
}
public static class GenericBarFactory<T> implements FactoryBean<GenericBar<T>> {
private Class<T> type;
public GenericBarFactory(Class<T> type) {
this.type = type;
}
@Override
public GenericBar<T> getObject() {
return new GenericBar<>(type);
}
@Override
public Class<?> getObjectType() {
return type;
}
}
public static class ClassWithGenericBar {
@Autowired
GenericBar<String> stringGenericBar;
@Autowired
GenericBar<Integer> integerGenericBar;
}
}
And I got exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.guice.FactoryTests$GenericBar<java.lang.String>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:636)
... 36 more
Is this an expected behavior or a bug?
Comment From: snicoll
The object type exposed by your FactoryBean
is the type argument. So, looking at your example, you expose that the first factory bean exposes a String
and the second one exposes an Integer
. There is no link between GenericBarFactory<String>
and GenericBar<String>
so it makes sense the injection there doesn't work.