[groovy-user] Baffling IllegalAccessException deep in the bowels of Groovy

110 views
Skip to first unread message

Keith Suderman

unread,
May 12, 2014, 7:27:58 PM5/12/14
to us...@groovy.codehaus.org
I am writing a processing resource (aka plugin) for a Java framework (http://gate.ac.uk) that I use frequently. The plugin is written in Java but makes use of a module written in Groovy that is deployed to our local Nexus repository. I use the Groovy module in several other Java projects with no problems. However, when I try to use my Java plugin in GATE I am getting the following exception:

Exception in thread "ApplicationViewer1" java.lang.IllegalAccessError: tried to access field org.codehaus.groovy.reflection.CachedClass.EMPTY from class org.codehaus.groovy.reflection.ClassInfo
at org.codehaus.groovy.reflection.ClassInfo.<init>(ClassInfo.java:49)
at org.codehaus.groovy.reflection.ClassInfo$LocalMap.<clinit>(ClassInfo.java:357)
at org.codehaus.groovy.reflection.ClassInfo$ThreadLocalMapHandler.initialValue(ClassInfo.java:405)
at org.codehaus.groovy.reflection.ClassInfo$ThreadLocalMapHandler.initialValue(ClassInfo.java:401)
at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:160)
at java.lang.ThreadLocal.get(ThreadLocal.java:150)
at org.codehaus.groovy.reflection.ClassInfo$ThreadLocalMapHandler.get(ClassInfo.java:419)
at org.codehaus.groovy.reflection.ClassInfo.getClassInfo(ClassInfo.java:99)
at org.anc.lapps.serialization.Container.$getStaticMetaClass(Container.groovy)
at org.anc.lapps.serialization.Container.<init>(Container.groovy)
at org.anc.lapps.gate.GateSerializer.convertToContainer(GateSerializer.java:39)
at org.anc.lapps.gate.LappsProcessingResource.execute(LappsProcessingResource.java:114)
at gate.util.Benchmark.executeWithBenchmarking(Benchmark.java:291)
at gate.creole.SerialController.runComponent(SerialController.java:221)
at gate.creole.SerialController.executeImpl(SerialController.java:153)
at gate.creole.AbstractController.execute(AbstractController.java:75)
at gate.util.Benchmark.executeWithBenchmarking(Benchmark.java:291)
at gate.gui.SerialControllerEditor$RunAction$1.run(SerialControllerEditor.java:1619)
at java.lang.Thread.run(Thread.java:724)

The org.anc.lapps.serialization classes use Jackson to serialize object to/from JSON.

Maybe I am doing something wrong, but this looks like a bug in Groovy… Do any Groovy gurus know what is going wrong here as I don’t even know where to begin to fix this (other than rewriting everything in pure Java).

I will attempt to develop a "simple" program that exhibits the problem, but that might no be easy to do given the number of separate programs/modules that are interacting.

Sincerely,
Keith Suderman

------------------------------
Research Associate
Department of Computer Science
Vassar College
Poughkeepsie, NY



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Jim White

unread,
May 12, 2014, 11:28:46 PM5/12/14
to us...@groovy.codehaus.org
Problem reports should include at least what version of Groovy and what JDK you're using.  However in this case that probably doesn't matter since this looks very much like a classloader problem in your configuration in which there are two copies of the Groovy classes.  

The member EMPTY has package scope and both ClassInfo and CachedClass are in the same package - at least at the source level.  So for this error to occur the classes are almost certainly in different classloaders:


The Jackson and JSON stuff doesn't seem relevant here.  I would check how the CLASSPATH gets set up when GATE is run and especially if there are any plugins configured.  Perhaps there are two different versions of Groovy in the classpath (one in the environment and another inside GATE?) which could easily cause this kind of trouble.

I use GATE and Groovy myself with no problems and so I can definitely say it is not necessary to abandon Groovy.   I like using GATE for the IDE and run GATE pipelines with Groovy and have made a Gradle task that makes that easy to do (although not yet turned into a separate item with docs of course ;-).  An example in the splitSentences task in the build.gradle here:


The SplitJavadocSentences task class written in Groovy is in buildSrc here.

A simpler example is running a GATE pipeline and taking the output to display in a web page here (Groovy with the Ratpack Framework):


The GATE specific stuff is in GATE_Processor.groovy here.

Jim

Jochen Theodorou

unread,
May 13, 2014, 2:29:25 AM5/13/14
to us...@groovy.codehaus.org
Am 13.05.2014 01:27, schrieb Keith Suderman:
> I am writing a processing resource (aka plugin) for a Java framework (http://gate.ac.uk) that I use frequently. The plugin is written in Java but makes use of a module written in Groovy that is deployed to our local Nexus repository. I use the Groovy module in several other Java projects with no problems. However, when I try to use my Java plugin in GATE I am getting the following exception:
>
> Exception in thread "ApplicationViewer1" java.lang.IllegalAccessError: tried to access field org.codehaus.groovy.reflection.CachedClass.EMPTY from class org.codehaus.groovy.reflection.ClassInfo
> at org.codehaus.groovy.reflection.ClassInfo.<init>(ClassInfo.java:49)

let's see... EMPTY is a package private field and CachedClass is in the
same package as ClassInfo, thus access is basically legal.

[...]
> The org.anc.lapps.serialization classes use Jackson to serialize object to/from JSON.
>
> Maybe I am doing something wrong, but this looks like a bug in Groovy… Do any Groovy gurus know what is going wrong here as I don’t even know where to begin to fix this (other than rewriting everything in pure Java).
>
> I will attempt to develop a "simple" program that exhibits the problem, but that might no be easy to do given the number of separate programs/modules that are interacting.

I think what you have is the problem that you have Groovy loaded two
times by different class loaders. package private access like above is
legal only, if the access is done from classes in the same package and
the same defining class loader. As it seems your ClassInfo class and
your CachedClass classes are loaded through different loaders and they
have now interactions that should not happen.

The question is why this happens. This surely does not happen for Groovy
in a normal case. Jackson might be a candidate, but I doubt Jackson goes
and defines new class loaders of its own. On top of that, to provoke
such an error you need class loaders violating the normal behaviour.
Normally a classloader is supposed to ask its parent for loading a class
first, that's exactly to prevent such errors.

Such behaviour you can find in Groovy only when using RootLoader, but
with that loader I am unsure how to get such a construction - plus it is
used for command line programs only. Imho something is messing with
class loaders big times in your application. My best bet would be that
the loaders you use for deserialization are at fault.

bye blackdrag

--
Jochen "blackdrag" Theodorou - Groovy Project Tech Lead
blog: http://blackdragsview.blogspot.com/
german groovy discussion newsgroup: de.comp.lang.misc
For Groovy programming sources visit http://groovy-lang.org

Keith Suderman

unread,
May 13, 2014, 2:12:07 PM5/13/14
to us...@groovy.codehaus.org
Thanks for the responses. I am including Groovy in my plugin; if I don’t I get the following exception:

Exception in thread "ApplicationViewer1" java.lang.NoClassDefFoundError: org/codehaus/groovy/runtime/callsite/CallSiteArray
at org.anc.lapps.serialization.Container.$createCallSiteArray(Container.groovy)
at org.anc.lapps.serialization.Container.$getCallSiteArray(Container.groovy)
at org.anc.lapps.serialization.Container.__$swapInit(Container.groovy)
at org.anc.lapps.serialization.Container.<clinit>(Container.groovy)
at org.anc.lapps.gate.GateSerializer.convertToContainer(GateSerializer.java:39)
at org.anc.lapps.gate.LappsProcessingResource.execute(LappsProcessingResource.java:114)
at gate.util.Benchmark.executeWithBenchmarking(Benchmark.java:291)
at gate.creole.SerialController.runComponent(SerialController.java:221)
at gate.creole.SerialController.executeImpl(SerialController.java:153)
at gate.creole.AbstractController.execute(AbstractController.java:75)
at gate.util.Benchmark.executeWithBenchmarking(Benchmark.java:291)
at gate.gui.SerialControllerEditor$RunAction$1.run(SerialControllerEditor.java:1619)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.ClassNotFoundException: org.codehaus.groovy.runtime.callsite.CallSiteArray
at gate.util.GateClassLoader.loadClass(GateClassLoader.java:199)
at gate.util.GateClassLoader.loadClass(GateClassLoader.java:122)
... 13 more

I took a quick look at the GATE source code and it does not appear to be bundling Groovy directly, and the above exception would seem to confirm that. The GateClassLoader also seems to be delegating to the parent ClassLoader and only attempting to load classes if the parent is unable to. The GATE Groovy plugin (which I do not enable) uses a really old version of Groovy (1.7.6) so it might be time for me to take this to the GATE mailing list and see what they have to say about this.

For completeness I am using Groovy 2.2.0, Java 1.7.0_25, Gate Developer 7.1 on Mac OS X 10.9.2

@Jim: I have been using Groovy + GATE successfully for some time as well, in fact I’ve written a little DSL that I use to automate GATE processing. However, this is the first time that I’ve tried writing a GATE plugin in Groovy.

Thanks for the assistance,
Keith
------------------------------
Research Associate
Department of Computer Science
Vassar College
Poughkeepsie, NY



Jim White

unread,
May 13, 2014, 2:41:49 PM5/13/14
to us...@groovy.codehaus.org
Yeah, looks like this is a classloader issue with how GATE loads plugins.  The key bit may be that the serialization stuff is loaded in a different child loader than your plugin.  A workaround could be to put Groovy in the CLASSPATH for GATE itself so that it winds up in the root loader and omit it from your plugin, at least until you sort out the issue.  I think you can that do by dropping groovy-all-2.2.0.jar into $GATE_HOME/lib, although you may need to cherry pick from $GROOVY_HOME/lib to avoid duplicating some dependencies.

Jim

Keith Suderman

unread,
May 13, 2014, 4:24:41 PM5/13/14
to us...@groovy.codehaus.org
Yes, it appears the solution is to put the groovy-all jar in $GATE_HOME/lib and not bundle it with my plugin.  This is a less than optimal solution for me, but that is a topic for the GATE mailing list.

Thanks for all your help.
Cheers,
Keith
Reply all
Reply to author
Forward
0 new messages