You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The BeanFactory.getBeanNamesForAnnotation() method has been causing issues. Here's a test case:
public class BeansWithAnnotationTests {
private AnnotationConfigApplicationContext context;
@After
public void close() {
if (context != null) {
context.close();
}
}
@Test // Fails
public void testWithImporter() {
context = new AnnotationConfigApplicationContext(Wrapper.class);
assertEquals("foo", context.getBean("value"));
}
@Test // Passes
public void testWithoutImporter() {
context = new AnnotationConfigApplicationContext(Config.class);
assertEquals("foo", context.getBean("value"));
}
@Configuration
@Import(Selector.class)
protected static class Wrapper {
}
protected static class Selector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {Config.class.getName() };
}
}
@Configuration
protected static class Config {
public Config() {
// Just so I can put a breakpoint here
System.getProperty("foo");
}
@Bean
public FooFactoryBean foo() {
return new FooFactoryBean();
}
@Bean
public String value() throws Exception {
String name = foo().getObject().getName();
Assert.state(name != null, "Name cannot be null");
return name;
}
@Bean
@Conditional(NoBarCondition.class)
public String bar() throws Exception {
return "bar";
}
}
protected static class NoBarCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getBeanFactory().getBeanNamesForAnnotation(Bar.class).length > 0) {
return false;
}
return true;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
protected static @interface Bar {
}
protected static class FooFactoryBean implements FactoryBean<Foo>, InitializingBean {
private Foo foo = new Foo();
@Override
public Foo getObject() throws Exception {
return foo;
}
@Override
public Class<?> getObjectType() {
return Foo.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void afterPropertiesSet() throws Exception {
this.foo.name = "foo";
}
}
protected static class Foo {
private String name;
public String getName() {
return name;
}
}
}
You need a perfect storm of a FactoryBean as a @Bean inside a @Configuration that was ImportSelected for this to break (I tried quite a few other scenarios). The passing test works because Spring doesn't try to instantiate the Config object.
It looks like there is an easy enough solution, blocking the early creation of FactoryBeans for type checking purposes if they are coming from a factory method on yet another bean. Basically it's whether "freezeConfiguration()" happened already: Before that point, we'll be conservative; afterwards we'll proceed as usual with respect to FactoryBean initialization. Condition evaluation happens before, whereas regular autowiring happens afterwards.
This makes your test pass, and is hopefully generally a fine measure.
Dave Syer opened SPR-11202 and commented
The BeanFactory.getBeanNamesForAnnotation() method has been causing issues. Here's a test case:
You need a perfect storm of a FactoryBean as a
@Bean
inside a@Configuration
that was ImportSelected for this to break (I tried quite a few other scenarios). The passing test works because Spring doesn't try to instantiate the Config object.Affects: 4.0 RC2
Issue Links:
Referenced from: commits 106a973
The text was updated successfully, but these errors were encountered: