Wednesday, 4 April 2012

Run your compiled Groovy code

I've lost some time today figuring out this, so I thought I would share it in case it can be helpful to someone.
Usually you run your Groovy code just by invoking groovy.exe on it. It takes care of loading your .groovy files and compile them on the fly. If you check the class loader for a Groovy class loaded this way [myInstance.class.classLoader] you'll see it's the groovy.lang.GroovyClassLoader.InnerLoader. This class has a doParse (private Class doParseClass(GroovyCodeSource codeSource) method that seems to compile your groovy class to in memory java bytecodes. If you want to check these bytecodes generated by groovy (it's really important if you want to get some insight on how Groovy does all its magic) you'll need a .class file that you can open with this nice Java Decompiler for instance. You can use groovyc to obtain those .class files.

Let's say we have this CheckClassLoader groovy code

class Person{
 def name;
}

println  "Checking ClassLoader";
p1 = new Person();
println p1.class.classLoader

running groovyc CheckClassLoader.groovy we'll get 2 .class files: Person.class and CheckClassLoader.class, one for each class generated by groovy.

I understand most people use these .class files not for decompiling them, but to launch them faster (you compile ahead of time just once and save all the time groovy spends doing the runtime compilation to bytecodes each time it loads one class...), so, how do you run your .class file generated by Groovyc?

Obviously you just invoke java.exe on it, as you would do with any .class generated by javac. The problem is that you need to add to your classpath the Groovy runtime library (the groovy.exe, groovyc.exe and groovysh.exe already take care of referencing them when launched, so that's why probably you should have never cared about this before...). Well, after some efforts, I finally found this document explaining where to find it, in my case: C:\Program Files\Groovy\Groovy-1.8.6\embeddable\

I'm not much experienced with Java, but I think the modern best practice is not to add things to the CLASSPATH environment variable and pass whatever you need to the compiler or the launcher with the -classpath switch, so I ended up with this:

java -classpath ".;C:\Program Files\Groovy\Groovy-1.8.6\embeddable\*" CheckClassLoader

notice that we have to add the current folder to the classpath, as when using the -classpath all the default classpath values (that includes the current folder) are overriden

When run this way, the class loader for your groovy class is not the GroovyClassLoader anymore, but the normal sun.misc.Launcher.AppClassLoader

No comments:

Post a Comment