I am currently migrating a fairly large application from Spring 3.0.0 to Spring 3.0.5. It's generally going well, but I am having difficulty with a few test cases that are using the annotation approach to bootstrapping the container:
The issue is that a bean post processor (an instance of ConfigurationClassPostProcessor) is having its postProcessBeanDefinitionRegistry operation invoked twice. On the second attempt it's blowing up with an IllegalStateException. The trouble is I have no idea what is causing it to be run twice.Code:@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:myapp/application-context.xml" }) @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) @Transactional public abstract class AbstractPublishingIntegrationTest { ... }
The first time it is invoked, this is the stack trace:
I've highlighted the line that appears to be particularly important. The second time the operation is invoked, this is the stack trace:Code:Thread [main] (Suspended (breakpoint at line 133 in ConfigurationClassPostProcessor)) ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry) line: 133 GenericApplicationContext(AbstractApplicationContext).invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) line: 599 GenericApplicationContext(AbstractApplicationContext).refresh() line: 407 GenericXmlContextLoader(AbstractGenericContextLoader).loadContext(String...) line: 84 GenericXmlContextLoader(AbstractGenericContextLoader).loadContext(String...) line: 1 TestContext.loadApplicationContext() line: 280 TestContext.getApplicationContext() line: 304 DependencyInjectionTestExecutionListener.injectDependencies(TestContext) line: 109 DependencyInjectionTestExecutionListener.prepareTestInstance(TestContext) line: 75 TestContextManager.prepareTestInstance(Object) line: 321 SpringJUnit4ClassRunner.createTest() line: 220 SpringJUnit4ClassRunner$1.runReflectiveCall() line: 301 SpringJUnit4ClassRunner$1(ReflectiveCallable).run() line: 15 SpringJUnit4ClassRunner.methodBlock(FrameworkMethod) line: 303 SpringJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 240 SpringJUnit4ClassRunner(BlockJUnit4ClassRunner).runChild(Object, RunNotifier) line: 44 SpringJUnit4ClassRunner(ParentRunner<T>).runChildren(RunNotifier) line: 180 ParentRunner<T>.access$000(ParentRunner, RunNotifier) line: 41 ParentRunner$1.evaluate() line: 173 RunBefores.evaluate() line: 28 RunBeforeTestClassCallbacks.evaluate() line: 61 RunAfters.evaluate() line: 31 RunAfterTestClassCallbacks.evaluate() line: 70 SpringJUnit4ClassRunner(ParentRunner<T>).run(RunNotifier) line: 220 SpringJUnit4ClassRunner.run(RunNotifier) line: 180 JUnit4TestClassReference(JUnit4TestReference).run(TestExecution) line: 46 TestExecution.run(ITestReference[]) line: 38 RemoteTestRunner.runTests(String[], String, TestExecution) line: 467 RemoteTestRunner.runTests(TestExecution) line: 683 RemoteTestRunner.run() line: 390 RemoteTestRunner.main(String[]) line: 197
Again, the highlighted line seems particularly relevant. Basically, we seem to be running through the method AbstractApplicationContext.refresh(), and the bean post processor is indirectly being invoked twice within that method. The source of that method is this:Code:Thread [main] (Suspended (breakpoint at line 133 in ConfigurationClassPostProcessor)) ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry) line: 133 ChildApplicationContextFactory$ChildApplicationContext(AbstractApplicationContext).invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) line: 586 ChildApplicationContextFactory$ChildApplicationContext(AbstractApplicationContext).refresh() line: 407 ChildApplicationContextFactory$ApplicationContextState.start() line: 684 ChildApplicationContextFactory(AbstractPropertyBackedBean).start(boolean) line: 665 ChildApplicationContextFactory(AbstractPropertyBackedBean).getState(boolean) line: 234 ChildApplicationContextFactory.getApplicationContext() line: 368 SubsystemProxyFactory$1.invoke(MethodInvocation) line: 60 ReflectiveMethodInvocation.proceed() line: 172 JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 202 $Proxy9.subsituteHost(String) line: not available NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25 Method.invoke(Object, Object...) line: 597 CglibSubclassingInstantiationStrategy(SimpleInstantiationStrategy).instantiate(RootBeanDefinition, String, BeanFactory, Object, Method, Object[]) line: 145 ConstructorResolver.instantiateUsingFactoryMethod(String, RootBeanDefinition, Object[]) line: 570 DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).instantiateUsingFactoryMethod(String, RootBeanDefinition, Object[]) line: 983 DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBeanInstance(String, RootBeanDefinition, Object[]) line: 879 DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).doCreateBean(String, RootBeanDefinition, Object[]) line: 485 DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBean(String, RootBeanDefinition, Object[]) line: 456 AbstractBeanFactory$1.getObject() line: 291 DefaultListableBeanFactory(DefaultSingletonBeanRegistry).getSingleton(String, ObjectFactory) line: 222 DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class<T>, Object[], boolean) line: 288 DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 190 DefaultListableBeanFactory.preInstantiateSingletons() line: 580 GenericApplicationContext(AbstractApplicationContext).finishBeanFactoryInitialization(ConfigurableListableBeanFactory) line: 895 GenericApplicationContext(AbstractApplicationContext).refresh() line: 425 GenericXmlContextLoader(AbstractGenericContextLoader).loadContext(String...) line: 84 GenericXmlContextLoader(AbstractGenericContextLoader).loadContext(String...) line: 1 TestContext.loadApplicationContext() line: 280 TestContext.getApplicationContext() line: 304 DependencyInjectionTestExecutionListener.injectDependencies(TestContext) line: 109 DependencyInjectionTestExecutionListener.prepareTestInstance(TestContext) line: 75 TestContextManager.prepareTestInstance(Object) line: 321 SpringJUnit4ClassRunner.createTest() line: 220 SpringJUnit4ClassRunner$1.runReflectiveCall() line: 301 SpringJUnit4ClassRunner$1(ReflectiveCallable).run() line: 15 SpringJUnit4ClassRunner.methodBlock(FrameworkMethod) line: 303 SpringJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 240 SpringJUnit4ClassRunner(BlockJUnit4ClassRunner).runChild(Object, RunNotifier) line: 44 SpringJUnit4ClassRunner(ParentRunner<T>).runChildren(RunNotifier) line: 180 ParentRunner<T>.access$000(ParentRunner, RunNotifier) line: 41 ParentRunner$1.evaluate() line: 173 RunBefores.evaluate() line: 28 RunBeforeTestClassCallbacks.evaluate() line: 61 RunAfters.evaluate() line: 31 RunAfterTestClassCallbacks.evaluate() line: 70 SpringJUnit4ClassRunner(ParentRunner<T>).run(RunNotifier) line: 220 SpringJUnit4ClassRunner.run(RunNotifier) line: 180 JUnit4TestClassReference(JUnit4TestReference).run(TestExecution) line: 46 TestExecution.run(ITestReference[]) line: 38 RemoteTestRunner.runTests(String[], String, TestExecution) line: 467 RemoteTestRunner.runTests(TestExecution) line: 683 RemoteTestRunner.run() line: 390 RemoteTestRunner.main(String[]) line: 197
Again, relevant lines highlighted.Code:try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); }
So the question is: does anyone know what might possibly be causing the post processor to be invoked twice from this code? I'm sure it goes without saying, but the tests were working correctly when using Spring 3.0.0.
All ideas and suggestions very gratefully received.
Brian


Reply With Quote