ColinMc ColinMc - 5 months ago 33
Java Question

Compile Groovy class at runtime in Java

I am successfully able to compile Groovy in Java at runtime and store it in a database and pull it out. I can't compile a Groovy class if it has inner classes or an inner enum. Has anyone successfully compiled Groovy code like this and included inner classes/enums and able to pull the script out by classname?

For example, I want to load the "Test" script shown below that contains inner classes and run the script at run time.

Compiler code:

public byte[] compileGroovyScript(final String className, final String script) {
byte[] compiledScriptBytes = null;
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(className, script);
compileUnit.compile(Phases.CLASS_GENERATION);

for (Object compileClass : compileUnit.getClasses()) {
GroovyClass groovyClass = (GroovyClass) compileClass;
compiledScriptBytes = groovyClass.getBytes();
}

return compiledScriptBytes;
}


Code to pull script out:

public Class getGroovyScript(final String className, final byte[] script) {
Class clazz = null;

try (GroovyClassLoader classLoader = new GroovyClassLoader(this.getClass().getClassLoader())) {
clazz = classLoader.defineClass(className, script);
} catch (IOException e) {
} catch (Exception e) {
}

return clazz;
}


Code to run the script:

Class groovyClass = app.getGroovyScript(className, compiledScript);
TestScript script = (TestScript) groovyClass.newInstance();
System.out.println(script.getMessage());


Groovy script:

import com.groovy.groovy.TestScript

class Test implements TestScript {

String getMessage() {
[1..10].each(){
println it
}
return "Jello"
}
}

Answer

It isn't clear from the description why you are doing the compiling yourself. If you can just let Groovy do it for you then the whole thing can just be simplified to something like this:

String script = // string containing the script you want to parse

GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Class theParsedClass = groovyClassLoader.parseClass(script);
Comments