-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Description
Benoit Lacelle opened SPR-11951 and commented
Hello,
If one has a BeanPostProcessor which returns null, then the laoding of the application contact would break with an exception not clear before knowing the actual issue.
Running the following test, :
@Configuration
public static class ConfigA {
@Bean
public String string() {
return "gogo";
}
}
@Configuration
public static class ConfigB {
@Bean
public BeanPostProcessor beanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
};
}
}
@Test
public void testInvalidConfig() {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigA.class, ConfigB.class)) {
}
}
one would get
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'string' defined in class blasd.apex.server.config.spring.autonomy.TestApexSourceConfigAutonomy$ConfigA: factory-bean 'testApexSourceConfigAutonomy.ConfigA' returned null
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:372)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
at blasd.apex.server.config.spring.autonomy.TestApexSourceConfigAutonomy.testInvalidConfig(TestApexSourceConfigAutonomy.java:118)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
This seems trivial, but I got an equivalent issue while using Mockito to mock an interface, which I was unaware to be a BeanPostProcessor: Mockito returned null on postProcessBeforeInitialization, leading to this issue but the error message (and even debugging) took me a few hours to understand what was happening.
Instead of "Error creating bean with name 'string' defined in class blasd.apex.server.config.spring.autonomy.TestApexSourceConfigAutonomy$ConfigA: factory-bean 'testApexSourceConfigAutonomy.ConfigA' returned null", I would have expected something like "BeanPostProcessor named "beanPostProcessor" returned null for 'testApexSourceConfigAutonomy.ConfigA'"
Thanks
Affects: 3.2.9, 4.0.3
Referenced from: commits 83a7deb, 077c624, 6c41cc3
Backported to: 3.2.10
Activity
spring-projects-issues commentedon Jul 4, 2014
Stéphane Nicoll commented
Your
PostProcessor
does not seem very realistic to me. You are basically saying that any bean that the context processes should be nullified. This includes Spring's own internal beans that it registers in the context. In the case of your particular test, you are settingorg.springframework.context.annotation.ConfigurationClassPostProcessor
tonull
. So you're basically preventing the@Configuration
classes to be processed at all.If you change your
PostProcessor
to nullify what it needs, this just work as it should, i.e.Then your context start and you get a
null
"string" bean.There's nothing wrong to return
null
there. In certain circumstances (i.e. factory bean), that might give weird results but I am not sure we can do something about it: the method that calls the post processor has no knowledge about the bean (and it shouldn't).spring-projects-issues commentedon Jul 4, 2014
Benoit Lacelle commented
Hi Stéphane,
I agree my BeanPostProcessor is not relevant. It was just for the sake of the unit-test readablity.
My usecase is less trivial: I have some interface like the following:
I don't own it, so I did not know it was a BeanPostProcessor.
My actual unit-test was like the following:
Given the error message, I was not lead to understand SomeBean was the BeanPostProcessor returning null.
Maybe we should check ConfigurationClassPostProcessor beans are never turned to null.
My question was rather: could we improve the error message?
By 'Error creating bean with name 'string' defined in class blasd.apex.server.config.spring.autonomy.TestApexSourceConfigAutonomy$ConfigA: factory-bean 'testApexSourceConfigAutonomy.ConfigA' returned null', I understand that "testApexSourceConfigAutonomy.ConfigA" returned a null instance. While the issue is "'beanPostProcessor' returned a null instance for 'testApexSourceConfigAutonomy.ConfigA'"
spring-projects-issues commentedon Jul 4, 2014
Benoit Lacelle commented
I re-open just to be sure if it is possible to improve the error message. I agree it works as designed.
spring-projects-issues commentedon Jul 4, 2014
Juergen Hoeller commented
I've reworded the exception's message to
"factory-bean 'myBean' (or a BeanPostProcessor involved) returned null"
We don't clearly know why we got a null result at that point of processing (since we're obtaining another bean instance there, constructed completely independently, with no context transferred to us)... but we can at least point out that a BeanPostProcessor may have been involved.
Juergen