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
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:
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:
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.
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.
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.
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?
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?
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:
This seems to be associated with a StackOverFlowException where the stack looks something like the following:
Notice that the following two lines are invoked repeatedly:
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:
Will randomly produce the following values for cglibMethodProxy:
This causes an infinite recursion, but the following value for cglibMethodProxy works:
Additional Notes:
Affects: 3.2.1
Issue Links:
Referenced from: commits spring-attic/spring-framework-issues@bd98e51, spring-attic/spring-framework-issues@a0e257c
The text was updated successfully, but these errors were encountered: