Skip to content

Periodic NoClassDefFoundError: FatalBeanException caused by StackOverFlowException [SPR-10261] #14894

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Feb 5, 2013 · 3 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Feb 5, 2013

Rob Winch opened SPR-10261 and commented

Despite having consistent Spring versions and ensuring I have spring-core-3.2.1.RELEASE.jar on the classpath, when loading Java Configuration, I occassionally get the following Error:

java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1029)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:925)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
	at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:73)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
	at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
	at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:71)
	at org.codehaus.groovy.runtime.callsite.ConstructorSite.callConstructor(ConstructorSite.java:42)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:54)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
	at groovy.groovy.GroovyReturnsSubclassTests.returnsSubclass(GroovyReturnsSubclassTests.groovy:16)
	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:601)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
	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:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

This seems to be associated with a StackOverFlowException where the stack looks something like the following:

                                                                                ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 297	
                                                                GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8.builder() line: not available	
                                                                                                    GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8(GroovyReturnsSubclassTests$MyConfig).builder() line: not available	
                                                                        GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8.CGLIB$builder$6() line: not available	
                                                                                                                GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8$$FastClassByCGLIB$$2a4c4776.invoke(int, Object, Object[]) line: not available	
                        MethodProxy.invokeSuper(Object, Object[]) line: 228	
                                                                                ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 285	
                                                                GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8.builder() line: not available	
                                                                NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
                            NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57	
                                DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
            Method.invoke(Object, Object...) line: 601	
                                                                                                                                CglibSubclassingInstantiationStrategy(SimpleInstantiationStrategy).instantiate(RootBeanDefinition, String, BeanFactory, Object, Method, Object[]) line: 160	
                                                                    ConstructorResolver.instantiateUsingFactoryMethod(String, RootBeanDefinition, Object[]) line: 570	
                                                                                                                DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).instantiateUsingFactoryMethod(String, RootBeanDefinition, Object[]) line: 1029	
                                                                                                    DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBeanInstance(String, RootBeanDefinition, Object[]) line: 925	
                                                                                                DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).doCreateBean(String, RootBeanDefinition, Object[]) line: 490	
                                                                                            DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBean(String, RootBeanDefinition, Object[]) line: 461	
                AbstractBeanFactory$1.getObject() line: 295	
                                                                        DefaultListableBeanFactory(DefaultSingletonBeanRegistry).getSingleton(String, ObjectFactory) line: 223	
                                                                            DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class<T>, Object[], boolean) line: 292	
                                            DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 194	
                                                                                ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 297	
                                                                GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8.builder() line: not available	
                                                                                                    GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8(GroovyReturnsSubclassTests$MyConfig).builder() line: not available	
                                                                        GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8.CGLIB$builder$6() line: not available	
                                                                                                                GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8$$FastClassByCGLIB$$2a4c4776.invoke(int, Object, Object[]) line: not available	
                        MethodProxy.invokeSuper(Object, Object[]) line: 228	
                                                                                ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 285	
                                                                GroovyReturnsSubclassTests$MyConfig$$EnhancerByCGLIB$$3aca3be8.builder() line: not available	
                                                                NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
                            NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57	
                                DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
            Method.invoke(Object, Object...) line: 601	
                                                                                                                                CglibSubclassingInstantiationStrategy(SimpleInstantiationStrategy).instantiate(RootBeanDefinition, String, BeanFactory, Object, Method, Object[]) line: 160	
                                                                    ConstructorResolver.instantiateUsingFactoryMethod(String, RootBeanDefinition, Object[]) line: 570	
                                                                                                                DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).instantiateUsingFactoryMethod(String, RootBeanDefinition, Object[]) line: 1029	
                                                                                                    DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBeanInstance(String, RootBeanDefinition, Object[]) line: 925	
                                                                                                DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).doCreateBean(String, RootBeanDefinition, Object[]) line: 490	
                                                                                            DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBean(String, RootBeanDefinition, Object[]) line: 461	
                AbstractBeanFactory$1.getObject() line: 295	
                                                                        DefaultListableBeanFactory(DefaultSingletonBeanRegistry).getSingleton(String, ObjectFactory) line: 223	
                                                                            DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class<T>, Object[], boolean) line: 292	
                                            DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 194	
                                    DefaultListableBeanFactory.preInstantiateSingletons() line: 626	
                                                                                                            AnnotationConfigApplicationContext(AbstractApplicationContext).finishBeanFactoryInitialization(ConfigurableListableBeanFactory) line: 932	
                                                    AnnotationConfigApplicationContext(AbstractApplicationContext).refresh() line: 479	
                                    AnnotationConfigApplicationContext.<init>(Class<?>...) line: 73	
                                                                        NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]	
                                NativeConstructorAccessorImpl.newInstance(Object[]) line: 57	
                                    DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45	
                    Constructor<T>.newInstance(Object...) line: 525	
                CachedConstructor.invoke(Object[]) line: 77	
                            CachedConstructor.doConstructorInvoke(Object[]) line: 71	
                            ConstructorSite.callConstructor(Object, Object[]) line: 42	
                                            CallSiteArray.defaultCallConstructor(CallSite, Object, Object[]) line: 54	
                                AbstractCallSite.callConstructor(Object, Object[]) line: 182	
                            AbstractCallSite.callConstructor(Object, Object) line: 190	
                        GroovyReturnsSubclassTests.returnsSubclass() line: 16	
                                                                NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
                            NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57	
                                DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
            Method.invoke(Object, Object...) line: 601	
                FrameworkMethod$1.runReflectiveCall() line: 44	
                        FrameworkMethod$1(ReflectiveCallable).run() line: 15	
                                FrameworkMethod.invokeExplosively(Object, Object...) line: 41	
    InvokeMethod.evaluate() line: 20	
                                        BlockJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 76	
                                BlockJUnit4ClassRunner.runChild(Object, RunNotifier) line: 50	
ParentRunner$3.run() line: 193	
            ParentRunner$1.schedule(Runnable) line: 52	
                                            BlockJUnit4ClassRunner(ParentRunner<T>).runChildren(RunNotifier) line: 191	
                                ParentRunner<T>.access$000(ParentRunner, RunNotifier) line: 42	
        ParentRunner$2.evaluate() line: 184	
                                    BlockJUnit4ClassRunner(ParentRunner<T>).run(RunNotifier) line: 236	
                                            JUnit4TestClassReference(JUnit4TestReference).run(TestExecution) line: 50	
                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	

Notice that the following two lines are invoked repeatedly:

...
ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 297
...
BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 285
...
ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 297
...
BeanMethodInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 285

This seems to occur when ConfigurationClassEnhancer$BeanMethodInterceptor.intercept has a value referring to the superclass for cglibMethodProxy instead of the current class value. For example the following Groovy code:

public class GroovyReturnsSubclassTests {
    private AnnotationConfigApplicationContext context;

    @Test
    public void returnsSubclass() {
        context = new AnnotationConfigApplicationContext(MyConfig.class);
    }

    @Configuration
    static class MyConfig extends BaseConfig {
        @Bean
        public String builder() throws Exception {
            return null;
        }
    }

    @Configuration
    static abstract class BaseConfig {
        public abstract Object builder() throws Exception;
    }
}

Will randomly produce the following values for cglibMethodProxy:

cglibMethodProxy	MethodProxy  (id=57)	
	createInfo	MethodProxy$CreateInfo  (id=88)	
	fastClassInfo	null	
	initLock	Object  (id=97)	
	sig1	Signature  (id=102)	
		desc	"()Ljava/lang/Object;" (id=115)	
		name	"builder" (id=74)	
	sig2	Signature  (id=106)	
		desc	"()Ljava/lang/Object;" (id=115)	
		name	"CGLIB$builder$0" (id=137)	

This causes an infinite recursion, but the following value for cglibMethodProxy works:

cglibMethodProxy	MethodProxy  (id=57)	
	createInfo	MethodProxy$CreateInfo  (id=88)	
	fastClassInfo	null	
	initLock	Object  (id=96)	
	sig1	Signature  (id=101)	
		desc	"()Ljava/lang/String;" (id=114)	
		name	"builder" (id=73)	
	sig2	Signature  (id=103)	
		desc	"()Ljava/lang/String;" (id=114)	
		name	"CGLIB$builder$6" (id=135)

Additional Notes:

  • It appears to only occur with Groovy. It does not seem to happen with Java
  • If builder() defines the same return type for the sublcass and parent it seems to work
  • Sometimes it works just fine sometimes it fails with the NoClassDefFoundError: FatalBeanException
  • A configuration like this might be usefult to do something like this:
    @Configuration
    static class MyConfig extends BaseConfig {
        @Bean
        public String builder() throws Exception {
            return null;
        }
    }

    @Configuration
    static abstract class BaseConfig {
        @Bean
        public UsesBuilder usesBuilder() {
            Object b = builder();
            return new UsesBuilder(b);
        }
        public abstract Object builder() throws Exception;
    }
  • I will post a complete project that demonstrates the issue in the comments

Affects: 3.2.1

Issue Links:

Referenced from: commits spring-attic/spring-framework-issues@bd98e51, spring-attic/spring-framework-issues@a0e257c

@spring-projects-issues
Copy link
Collaborator Author

Rob Winch commented

I created spring-attic/spring-framework-issues#43 that demonstrates the issue. There are more details in the README and javadoc of the 3 tests in the project.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Turns out that this is indeed caused by a mismatch in that covariant return type: Sometimes the CglibMethodProxy refers to one variant whereas the container's currently invoked factory method points to the other variant. Since we've been comparing those two using 'Method.equals' to find out whether we're currently in a container invocation, we failed to detect a container invocation in that specific case and went through the container indirection once again... and again... and again.

I've changed that comparison to method name and parameter types now, ignoring the return type, so that we're detecting the container invocation in case of such a mismatch as well. I have been unable to make the test case fail ever since. Nevertheless, please also run the test again yourself.

Theoretically such a mismatch may occur with regular Java classes as well, simply due to JDK runtime differences in reflective method ordering during CGLIB introspection. So this is likely not just a fix for that Groovy case but rather a worthwhile change for defensiveness in general.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Rob Winch commented

Thanks for the fast turnaround. I can confirm that the issue is resolved in the 3.2.2.BUILD-SNAPSHOT. It does bring some additional questions to mind.

  1. Why does the CglibMethodProxy sometimes refer to one variant and other times others? Is this another bug that needs to be logged to cglib and/or Spring?
  2. I'm not sure if there is anything we can do to resolve the fact that the underlying issue was a StackOverflowException and the error that was reported was a NoClassDefFoundError. Do you think it is possible us to have a better error message here?

Obviously the two points don't change the fact that the issue is resolved, but I was curious if you had any thoughts about my questions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants