-
Notifications
You must be signed in to change notification settings - Fork 37.7k
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
ObjenesisCglibAopProxy's fallback mode triggers duplicate class definition error [SPR-13131] #17722
Comments
Juergen Hoeller commented More specifically, it's about using CGLIB without Objenesis... since That said, we do have a fallback path for regular CGLIB proxy instantiation if Objenesis fails for a given class. Does that not kick in on GAE for some reason? Or would you like to avoid the attempt to use Objenesis for efficiency reasons? Juergen |
Tobias Gesellchen commented You're right, it's about using CGLIB without Objenesis. We had issues even with the fallback, but I cannot remember the actual error. I'll investigate tomorrow and add more details here. |
Tobias Gesellchen commented It looks like GAE 9:36:22.027 WARNING com.google.apphosting.utils.jetty.JettyLogger warn : Nested in org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ourClass': Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.example.OurClass]: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null:
java.lang.LinkageError: loader (instance of com/google/appengine/tools/development/IsolatedAppClassLoader): attempted duplicate class definition for name: "com/example/OurClass$$EnhancerBySpringCGLIB$$fca8322"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:130)
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.CglibAopProxy.createProxyClassAndInstance(CglibAopProxy.java:227)
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:66) |
Tobias Gesellchen commented Another aspect to make the Objenesis vs. plain CGLIB implementation configurable would be performance. Since we know that Objenesis will always fail on GAE, we would prefer to disable it completely and set plain CGLIB as default. |
Juergen Hoeller commented This seems to be caused by CGLIB's Objenesis itself even caches its instantiation strategy, so pretty much auto-adapts to an environment where it can't do its regular job, assumably even without a significant performance penalty. In any case, I'd prefer for this to be auto-adaptive, with no need to explicitly configure the strategy on Google App Engine. Juergen |
Tobias Gesellchen commented Great to hear that you'll have a deeper look for 4.2! In case you need us to test the RC2 in our environment, just leave a note here. We would still prefer to have an option to explicitly select the |
Juergen Hoeller commented More specifically, an There is clearly something at odds here. I'll deal with it from two perspectives: For a start, the fallback needs to be defensive enough to reliably work, possibly reusing the Juergen |
Juergen Hoeller commented Objenesis itself basically checks whether That said, allowing for an explicit decision here is fine as well. It just shouldn't be necessary in any common environment, that's what I'm aiming for. Juergen |
Juergen Hoeller commented Tobias, could you please turn on debug logging for "org.springframework.aop.framework" to see the stacktrace for the Juergen |
Juergen Hoeller commented In the meantime, I got the fallback code path working through reuse of the It's now just about optimizing the detection of the need for a fallback in the first place. Spring 4.2 has some revised caching of Objenesis instantiators already but it'd be good to pre-detect the "fails always" case as well, not bothering with an Objenesis instantiation attempt and an individual fallback every time in such a scenario. |
Tobias Gesellchen commented the logs show this stacktrace: 15:11:31.717 [main] DEBUG o.s.a.f.ObjenesisCglibAopProxy - Unable to instantiate proxy using Objenesis, falling back to regular proxy construction
org.springframework.objenesis.ObjenesisException: java.lang.IllegalAccessException: Reflection is not allowed on public static sun.reflect.ReflectionFactory sun.reflect.ReflectionFactory.getReflectionFactory()
at org.springframework.objenesis.instantiator.sun.SunReflectionFactoryHelper.createReflectionFactory(SunReflectionFactoryHelper.java:78) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.objenesis.instantiator.sun.SunReflectionFactoryHelper.newConstructorForSerialization(SunReflectionFactoryHelper.java:39) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.<init>(SunReflectionFactoryInstantiator.java:38) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.objenesis.strategy.StdInstantiatorStrategy.newInstantiatorOf(StdInstantiatorStrategy.java:58) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.objenesis.ObjenesisBase.getInstantiatorOf(ObjenesisBase.java:91) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:202) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
...
Caused by: java.lang.IllegalAccessException: Reflection is not allowed on public static sun.reflect.ReflectionFactory sun.reflect.ReflectionFactory.getReflectionFactory()
at com.google.appengine.tools.development.agent.runtime.Runtime.verifyWhiteListed(Runtime.java:92) ~[appengine-agentruntime.jar:na]
at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:127) ~[appengine-agentruntime.jar:na]
at org.springframework.objenesis.instantiator.sun.SunReflectionFactoryHelper.createReflectionFactory(SunReflectionFactoryHelper.java:72) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE] with the fallback producing this stacktrace: Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.CglibAopProxy.createProxyClassAndInstance(CglibAopProxy.java:227) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:66) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:202) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
... 44 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_79]
at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:130) ~[appengine-agentruntime.jar:na]
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219) ~[spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE] |
Tobias Gesellchen commented as a side note: I'm testing locally with the appengine sdk: |
Tobias Gesellchen commented would you like us to check if the code path is different when run on the actual GAE and not locally? |
Juergen Hoeller commented Yes please, that would be great to know! The So the remaining interesting part is the Juergen |
Tobias Gesellchen commented looks like the expected Caused by: java.lang.NoClassDefFoundError: sun.reflect.ReflectionFactory is a restricted class. Please see the Google App Engine developer's guide for more details.
at com.google.appengine.runtime.Request.process-8527557b0ff645c5(Request.java) ~[na:na]
at sun.reflect.ReflectionFactory.<clinit>(ReflectionFactory.java) ~[na:na]
at java.lang.reflect.Method.invoke(Method.java:45) ~[na:1.7.0-google-v6]
at org.springframework.objenesis.instantiator.sun.SunReflectionFactoryHelper.createReflectionFactory(SunReflectionFactoryHelper.java:72) ~[spring-core-4.1.6.RELEASE.jar:na]
at org.springframework.objenesis.instantiator.sun.SunReflectionFactoryHelper.newConstructorForSerialization(SunReflectionFactoryHelper.java:39) ~[spring-core-4.1.6.RELEASE.jar:na]
at org.springframework.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.<init>(SunReflectionFactoryInstantiator.java:38) ~[spring-core-4.1.6.RELEASE.jar:na]
at org.springframework.objenesis.strategy.StdInstantiatorStrategy.newInstantiatorOf(StdInstantiatorStrategy.java:58) ~[spring-core-4.1.6.RELEASE.jar:na]
at org.springframework.objenesis.ObjenesisBase.getInstantiatorOf(ObjenesisBase.java:91) ~[spring-core-4.1.6.RELEASE.jar:na]
at org.springframework.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73) ~[spring-core-4.1.6.RELEASE.jar:na]
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57) ~[spring-aop-4.1.6.RELEASE.jar:na]
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:202) ~[spring-aop-4.1.6.RELEASE.jar:na] |
Juergen Hoeller commented Thanks for checking! So that seems to be the same exception as reported in easymock/objenesis#15 - alright, we'll do a broader check then, covering a directly propagated |
Tobias Gesellchen commented Ah, you're right, I didn't notice that the fallback code hasn't been triggered on production. So you would also backport to handle the |
Juergen Hoeller commented Yes, making sure the fallback code path reliably kicks in is a 4.1.7 topic, and handling this For 4.2, we'll additionally track general Objenesis failure and will efficiently bypass it afterwards. I'm also considering a "spring.objenesis.ignore" system property with a boolean value, along the lines of "spring.beaninfo.ignore" which we have in |
Tobias Gesellchen commented great, so I'm excited to check the upcoming releases. If you need more feedback or testing, please ask. Thanks for now! |
Juergen Hoeller commented We'll have 4.2 and 4.1.7 snapshots ready for testing tomorrow morning. 4.2 RC2 and 4.1.7 are scheduled for release on June 19 (i.e. this Friday), so your report came just in time :-) Juergen |
Tobias Gesellchen commented yay! :-) |
Juergen Hoeller commented The 4.2 story is complete now as per the description above, not just for CGLIB AOP proxies but also for CGLIB-created FactoryBean proxies in configuration classes and for controller proxies in the MVC URI component builder. All of the smart Objenesis handling has been baked into 4.2's new I'll let you know once the 4.1.7 backport is available. That part will be a local fix in Juergen |
Juergen Hoeller commented Tobias Gesellchen, this is available in the latest 4.2.0.BUILD-SNAPSHOT and 4.1.7.BUILD-SNAPSHOT now. It would be great if you could give it a try before Friday! Juergen |
Tobias Gesellchen commented Juergen, I gave 4.1.7.BUILD-SNAPSHOT a try, with success on my local environment. I'm afraid it won't work on production, because the fallback won't be triggered on a |
Juergen Hoeller commented Oops, indeed, the Juergen |
Juergen Hoeller commented The next 4.1.7 snapshot (ready in ~15 min) should have this properly addressed! Thanks for the immediate testing... |
Tobias Gesellchen commented It works on production now (with 4.1.7 snapshot), thanks for the quick fix! |
Tobias Gesellchen opened SPR-13131 and commented
With #15223 CGLIB has been replaced by Objenesis without the ability to configure CGLIB as proxy factory.
We would like to use CGLIB proxying in a GAE environment, where Objenesis isn't allowed. We didn't find the
org.springframework.aop.framework.DefaultAopProxyFactory
to be configurable for our needs, where theObjenesisCglibAopProxy
instantiation is hard coded.Would it be possible to allow the
org.springframework.aop.framework.CglibAopProxy
to be configured as default proxy factory?Affects: 4.1.6
Issue Links:
The text was updated successfully, but these errors were encountered: