Skip to content

Modification in AbstractAutowireCapableBeanFactory to prevent stackoverflow errors causes context not to load. [SPR-15125] #19692

Closed
@spring-projects-issues

Description

@spring-projects-issues
Collaborator

Jeff Maxwell opened SPR-15125 and commented

Modification in AbstractAutowireCapableBeanFactory to prevent StackOverflowErrors causes context not to load with org.springframework.beans.factory.NoSuchBeanDefinitionException.

This commit causes our code to throw the exception below.

Earlier versions of AbstractAutowireCapableBeanFactory work fine.

Note that the reference.service.instrumentEhcache bean is created via a subclass of org.springframework.cache.ehcache.EhCacheFactoryBean

The context being loaded is rather complex, I have not yet been able to create a minimal test example.

2017-01-10 11:24:38.991 17201 [main] ERROR o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@59d016c9] to prepare test instance [*.*.*.*.*.*.PositionAccountManagerTest@16ca4532]
java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
	at org.springframework.test.context.junit4.statements.RunPrepareTestInstanceCallbacks.evaluate(RunPrepareTestInstanceCallbacks.java:63)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.springframework.test.context.junit4.statements.SpringFailOnTimeout.evaluate(SpringFailOnTimeout.java:87)
	at org.springframework.test.context.junit4.statements.ProfileValueChecker.evaluate(ProfileValueChecker.java:101)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.springframework.test.context.junit4.statements.ProfileValueChecker.evaluate(ProfileValueChecker.java:101)
	at org.springframework.test.context.junit4.rules.SpringClassRule$TestContextManagerCacheEvictor.evaluate(SpringClassRule.java:242)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	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:678)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'reference.referenceCache' defined in URL [jar:file:/*/*/*/*/*/*/*/*/*/*.jar!/*/*/*/reference/cache/ReferenceCache.class]: Unsatisfied dependency expressed through constructor parameter 14: Error creating bean with name 'reference.service.instrumentCache' defined in URL [jar:file:/*/*/*/*/*/*/*/*/*/*.jar!/*/*/*/reference/cache/InstrumentCache.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [net.sf.ehcache.Ehcache] found for dependency [net.sf.ehcache.Ehcache]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=reference.service.instrumentEhcache)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.sf.ehcache.Ehcache] found for dependency [net.sf.ehcache.Ehcache]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=reference.service.instrumentEhcache)}; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'reference.service.instrumentCache' defined in URL [jar:file:/*/*/*/*/*/*/*/*/*/*.jar!/com/theice/cds/reference/cache/InstrumentCache.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [net.sf.ehcache.Ehcache] found for dependency [net.sf.ehcache.Ehcache]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=reference.service.instrumentEhcache)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.sf.ehcache.Ehcache] found for dependency [net.sf.ehcache.Ehcache]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=reference.service.instrumentEhcache)}
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1147)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1050)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:751)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128)
	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
	... 29 common frames omitted
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'reference.service.instrumentCache' defined in URL [jar:file:/*/*/*/*/*/*/*/*/*/*.jar!/*/*/*/reference/cache/InstrumentCache.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [net.sf.ehcache.Ehcache] found for dependency [net.sf.ehcache.Ehcache]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=reference.service.instrumentEhcache)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.sf.ehcache.Ehcache] found for dependency [net.sf.ehcache.Ehcache]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=reference.service.instrumentEhcache)}
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1147)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1050)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1239)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1079)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1044)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
	... 47 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.sf.ehcache.Ehcache] found for dependency [net.sf.ehcache.Ehcache]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=reference.service.instrumentEhcache)}
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1431)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1082)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1044)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
	... 62 common frames omitted

Affects: 4.3.3

Issue Links:

Referenced from: commits 32fc855, 24ebd15

Activity

spring-projects-issues

spring-projects-issues commented on Jan 11, 2017

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

#19119 was a rather important fix since prior to this change we completely bypassed getSingletonFactoryBeanForTypeCheck's currently-in-creation checks, leading to full initialization of the FactoryBean instance for type checking even in circular reference scenarios... with a stack overflow potential even if the type wouldn't match anyway.

So in your case, we seem to back out of checking your FactoryBean's type because we detect a currently-in-creation scenario. You could try to debug this with a breakpoint in getSingletonFactoryBeanForTypeCheck, stepping through the currently-in-creation conditions there.

Are you possibly declaring this FactoryBean on a configuration class, trying to wire its result into the configuration class itself? In such a scenario, please note that the only clean way out is declaring such an @Bean method as static, allowing its instance to be created without relying on a fully initialized configuration class instance around.

spring-projects-issues

spring-projects-issues commented on Jan 11, 2017

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

Or are you possibly trying to inject a FactoryBean's object outcome into that very same FactoryBean itself?

In any case, please show some configuration snippets for a clearer indication. There is something special about your setup that we do not have a unit test for.

spring-projects-issues

spring-projects-issues commented on Jan 12, 2017

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

I've added a lenient fallback to an early singleton reference of the currently created FactoryBean. Even if this is not recommended, with 4.3's self injection capabilities, it should arguably work.

This will make into tomorrow's 4.3.6.BUILD-SNAPSHOT. If your scenario still isn't working then, please reopen this issue.

spring-projects-issues

spring-projects-issues commented on Jan 12, 2017

@spring-projects-issues
CollaboratorAuthor

Jeff Maxwell commented

Are you possibly declaring this FactoryBean on a configuration class, trying to wire its result into the configuration class itself?

Not that I am aware.

Or are you possibly trying to inject a FactoryBean's object outcome into that very same FactoryBean itself?

It does not appear to do this.

In any case, please show some configuration snippets for a clearer indication. There is something special about your setup that we do not have a unit test for.

I have struggled to create a minimal unit test of this issue as the configuration/code base is rather labyrinthine.

I've added a lenient fallback to an early singleton reference of the currently created FactoryBean. Even if this is not recommended, with 4.3's self injection capabilities, it should arguably work.

I will pull and retest.

spring-projects-issues

spring-projects-issues commented on Jan 12, 2017

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

Unfortunately, there was still some stack overflow potential left, so I haven't committed any change yet. Self references to a FactoryBean - which is what I tested against there out of my wild guess - are inherently dangerous, it seems :-( I'll mark this issues as reopened.

The declarations of your EhCacheFactoryBean subclass and the point where you inject it would help me a lot. Otherwise the only way forward is debugging on your end.

spring-projects-issues

spring-projects-issues commented on Jan 13, 2017

@spring-projects-issues
CollaboratorAuthor

Jeff Maxwell commented

We believe that we have narrowed the issue a bit.
There are a couple of cache loaders, including our loader for reference.service.instrumentEhcache, that depend on other caches.
If we remove these dependencies from the reference.service.instrumentEhcache cache loader we do not see the issue.

Does this help?

spring-projects-issues

spring-projects-issues commented on Jan 16, 2017

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

I've added additional detection of statically declared FactoryBean types in bean class hierarchies as well as static factory methods. So instead of trying to create the full bean instance (which leads to a potential stack overflow), we're now falling back to static introspection if we can't create an early FactoryBean instance. This works fine for our unit tests and should work fine for a standard FactorBean variant like EhCacheFactoryBean as well, as long as the implementation hierarchy declares the FactoryBean's object type in some implements or extends clause.

I'll ping you once this is available in a 4.3.6.BUILD-SNAPSHOT. Would be great if you could give it an early try then...

spring-projects-issues

spring-projects-issues commented on Jan 16, 2017

@spring-projects-issues
CollaboratorAuthor

Juergen Hoeller commented

This is available in the latest 4.3.6.BUILD-SNAPSHOT now. Please give it a try if you have the chance...

(See http://projects.spring.io/spring-framework/ for how to obtain a snapshot from our snapshot repository.)

spring-projects-issues

spring-projects-issues commented on Jan 17, 2017

@spring-projects-issues
CollaboratorAuthor

Jeff Maxwell commented

It works.
Thanks for all your effort.

added this to the 4.3.6 milestone on Jan 11, 2019

1 remaining item

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: regressionA bug that is also a regression

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @jhoeller@spring-projects-issues

      Issue actions

        Modification in AbstractAutowireCapableBeanFactory to prevent stackoverflow errors causes context not to load. [SPR-15125] · Issue #19692 · spring-projects/spring-framework