groovy

NoClassDefFoundError as a side effect of a POJO method invocation

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Won't Fix
  • Affects Version/s: 1.5.6
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Number of attachments :
    0

Description

As a result of a POJO method call groovy.lang.MetaClassImpl.initialize() indirectly calls java.lang.Class.getDeclaredMethods().

This leads to a NoClassDefFoundError if one of the class' method signatures references a type that is not in the classpath - event though the method names are different.

The same code works in Java with the same classpath.

Activity

Hide
blackdrag blackdrag added a comment -

can you give an example for the POJO and explain which classes are in the classpath and which classes are not?

Show
blackdrag blackdrag added a comment - can you give an example for the POJO and explain which classes are in the classpath and which classes are not?
Hide
Alexander Veit added a comment -

The class that was in the classpath is
com.sap.mw.jco.JCO.Client
http://help.sap.com/javadocs/NW04S/current/jc/com/sap/mw/jco/JCO.Client.html

The class that was not in the classpath is
com.sap.jdsr.writer.DsrIPassport

Show
Alexander Veit added a comment - The class that was in the classpath is com.sap.mw.jco.JCO.Client http://help.sap.com/javadocs/NW04S/current/jc/com/sap/mw/jco/JCO.Client.html The class that was not in the classpath is com.sap.jdsr.writer.DsrIPassport
Hide
blackdrag blackdrag added a comment -

so it is the parameter class of a method, that is missing...

Show
blackdrag blackdrag added a comment - so it is the parameter class of a method, that is missing...
Hide
Alexander Veit added a comment -

Yes.

Show
Alexander Veit added a comment - Yes.
Hide
blackdrag blackdrag added a comment -

ok, verified the problem, and we have that since 1.0 already. I am not sure what we can do about that. But we can probably catch the exception and react accordingly.

Show
blackdrag blackdrag added a comment - ok, verified the problem, and we have that since 1.0 already. I am not sure what we can do about that. But we can probably catch the exception and react accordingly.
Hide
Alexander Veit added a comment -

I suspect that a lazy method population algorith - if possible - could slow down the Groovy runtime.

I don't know how severe the impact is in practice. Has a custumer who had licensed lib1.jar normally also had licensed the missing lib2.jar?

It's maybe a good idea to leave this issue open until it's relevance becomes more clear.

Show
Alexander Veit added a comment - I suspect that a lazy method population algorith - if possible - could slow down the Groovy runtime. I don't know how severe the impact is in practice. Has a custumer who had licensed lib1.jar normally also had licensed the missing lib2.jar? It's maybe a good idea to leave this issue open until it's relevance becomes more clear.
Hide
blackdrag blackdrag added a comment -

it doesn't need to be more lazy that it is atm... we just have to mark the method somehow, so the runtime knows that for this method not all classes are resolved. Any call to such a method results in an error anyway.

Show
blackdrag blackdrag added a comment - it doesn't need to be more lazy that it is atm... we just have to mark the method somehow, so the runtime knows that for this method not all classes are resolved. Any call to such a method results in an error anyway.
Hide
Alexander Veit added a comment -

Hmm, here's part of the stack trace we received:

Caused by: java.lang.NoClassDefFoundError: com/sap/jdsr/writer/DsrIPassport
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
at java.lang.Class.getDeclaredMethods(Class.java:1791)
at org.codehaus.groovy.reflection.CachedClass$1.run(CachedClass.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:171)
at groovy.lang.MetaClassImpl.populateMethods(MetaClassImpl.java:235)
at groovy.lang.MetaClassImpl.fillMethodIndex(MetaClassImpl.java:214)
at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:2478)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:253)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:765)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:754)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
at script1217180211687.run(script1217180211687.groovy:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
... 38 more
Caused by: java.lang.ClassNotFoundException: com.sap.jdsr.writer.DsrIPassport
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
... 62 more

From this i concluded that if java.lang.Class.getDeclaredMethods() would throw an error no method of the POJO would be visible from Groovy.

Show
Alexander Veit added a comment - Hmm, here's part of the stack trace we received: Caused by: java.lang.NoClassDefFoundError: com/sap/jdsr/writer/DsrIPassport at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2427) at java.lang.Class.getDeclaredMethods(Class.java:1791) at org.codehaus.groovy.reflection.CachedClass$1.run(CachedClass.java:174) at java.security.AccessController.doPrivileged(Native Method) at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:171) at groovy.lang.MetaClassImpl.populateMethods(MetaClassImpl.java:235) at groovy.lang.MetaClassImpl.fillMethodIndex(MetaClassImpl.java:214) at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:2478) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getGlobalMetaClass(MetaClassRegistryImpl.java:253) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.access$100(MetaClassRegistryImpl.java:45) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getFromGlobal(MetaClassRegistryImpl.java:112) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$LocallyKnownClasses.getMetaClass(MetaClassRegistryImpl.java:88) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$MyThreadLocal.getMetaClass(MetaClassRegistryImpl.java:361) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265) at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:765) at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:754) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170) at script1217180211687.run(script1217180211687.groovy:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86) ... 38 more Caused by: java.lang.ClassNotFoundException: com.sap.jdsr.writer.DsrIPassport at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319) ... 62 more From this i concluded that if java.lang.Class.getDeclaredMethods() would throw an error no method of the POJO would be visible from Groovy.
Hide
blackdrag blackdrag added a comment -

hmm.. that's true... I forgot that you can not simply get the method without getting all of them or by knowing the name... in that case I doubt we will find a solution for this.. unless the MetaClass is created in a very different way... like for example by using pre-calculated meta class information as some kind of database.

Show
blackdrag blackdrag added a comment - hmm.. that's true... I forgot that you can not simply get the method without getting all of them or by knowing the name... in that case I doubt we will find a solution for this.. unless the MetaClass is created in a very different way... like for example by using pre-calculated meta class information as some kind of database.
Hide
Alexander Veit added a comment -

... or using a different reflection library, if feasible, maybe objectweb asm.

Show
Alexander Veit added a comment - ... or using a different reflection library, if feasible, maybe objectweb asm.
Hide
blackdrag blackdrag added a comment -

objectweb asm is not a reflection library. You need the bytecode for the asm lib, if you do not have it, then you have a problem. Of course the bytecode exists somewhere and there is a way to get it if the class is loaded froma file and the classloader is generous enough to place the informations you need to find the .jar/.class and of course the asm lib has all this builtin already... but there are also cases when there is no file. If the class is generated at runtime or if the class comes from a db or whatever, then it will be a problem...

Well unless you know a way to get the bytecode as bye[] at runtime without the need of having the class as file somewhere. I would be very interested in knowing

Show
blackdrag blackdrag added a comment - objectweb asm is not a reflection library. You need the bytecode for the asm lib, if you do not have it, then you have a problem. Of course the bytecode exists somewhere and there is a way to get it if the class is loaded froma file and the classloader is generous enough to place the informations you need to find the .jar/.class and of course the asm lib has all this builtin already... but there are also cases when there is no file. If the class is generated at runtime or if the class comes from a db or whatever, then it will be a problem... Well unless you know a way to get the bytecode as bye[] at runtime without the need of having the class as file somewhere. I would be very interested in knowing
Hide
Alexander Veit added a comment -

The only place where the original class bytes can be seen is probably within ClassLoaders (where calls to the defineClass methods are made) or instrumentation agents (before defineClass calls). I doubt that the original class byte array is kept in memory by common ClassLoaders.

So, given current Groovy byte code, there's probably no chance to fix this bug in an efficient way unless the Java reflection API will provide a way to do so (e.g. by an alternative method iteration pattern, or by lazy instantiation of parameter, return and exception types within the Method class).

Show
Alexander Veit added a comment - The only place where the original class bytes can be seen is probably within ClassLoaders (where calls to the defineClass methods are made) or instrumentation agents (before defineClass calls). I doubt that the original class byte array is kept in memory by common ClassLoaders. So, given current Groovy byte code, there's probably no chance to fix this bug in an efficient way unless the Java reflection API will provide a way to do so (e.g. by an alternative method iteration pattern, or by lazy instantiation of parameter, return and exception types within the Method class).
Hide
Guillaume Laforge added a comment -

To create a meta class we need full reflective information. Even if we used asm to compile we would still run into this problem at runtime. Using asm for runtime code is not really an option.

Show
Guillaume Laforge added a comment - To create a meta class we need full reflective information. Even if we used asm to compile we would still run into this problem at runtime. Using asm for runtime code is not really an option.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: