Version 11, last updated by jpavuk at October 03, 2010 12:32 UTC
GroovyBytecode
Some references
- groovy site – lang spec, grammar diagrams
- outdated JSR 241
Loading .groovy files at runtime
We have to use GroovyClassLoader, e.g.:
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
Class groovyClass = loader.parseClass(new File("HelloWorld.groovy"));
Simplified steps (all this happens in the memory):
- .groovy file is fed into the Groovy parser → Abstract Syntax Tree created (AST)
- Groovy class generator takes AST and generates bytecode
- bytecode is given to the classloader and is available through the Groovy classloader
The same steps are executed with the Groovy interpreter (groovy), then the bytecode will be executed directly on the JVM.
The Groovy compiler (groovyc) executes only first two steps and stores the generated bytecode into .class file.
Groovy code after compilation
Points relevant for comparison:
1. def type
- is represented as Object
2. GroovyBeans
- for all properties without modifier are generated (a) attribute with private access level, (b) accessor methods (get, set) – both are public
- to have only readable property, it must be declared as final
- it works with all attributes – closures are affected too
3. Closures
- are represented as private inner classes which extend groovy.lang.Closure (each closure has own class) – they stores all parameters, closure body etc.
- in the bytecode we see them only as property of type Object (originally def)
- linking to they are initialized in the constructor of the owner class
4. Modifiers after compilation
- Attributes (incl. closures)
pritvate → private
none → private (public accessor methods are created)
public → public
- Methods
private → private
none → public
public → public
- Class
private → none
none → public
public → public
What can we get via reflection:
- the same as in Java
After instantiation of the class we can handle closures – they are initialized in the constructor – so we have proper instances of classes which extend groovy.lang.Closure in our attributes-
Syntactic differences Java x Groovy
There is only one syntactic difference relevant for our comparison – the closure.
How to obtain bytecode data from classloader
This solution:
final Class x = yourObject.getClass();
//create path to class file
final String className = x.getName().replaceAll("\\.", "/") + ".class";
final GroovyClassLoader cl = (GroovyClassLoader)x.getClassLoader();
final InputStream is = cl.getResourceAsStream(className);
byte[] buf = new byte[1024];
final ByteArrayOutputStream output = new ByteArrayOutputStream();
int len;
while ((len = is.read(buf)) != -1) {
output.write(buf);
}
is.close();
//byte[] of class bytecode
output.toByteArray();
is NOT working even if we have the .groovy file loaded with the GroovyClassloader (see Loading .groovy files at runtime), because there is no resource file with .class extension on the disk. If we try to use the class name with .goovy extension we will fail, too.
Here is the solution:
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(loader);
final CompilationUnit unit = new CompilationUnit(groovyClassLoader);
unit.addSource(new File("HelloWorld.groovy"));
unit.compile();
List classes = unit.getClasses();
for (final Iterator it = classes.iterator(); it.hasNext();) {
final GroovyClass clazz = (GroovyClass) it.next();
final byte[] bytes = clazz.getBytes();
}