I would like to know how to create an object Closureat runtime from a Java application where the contents of Closure are not known in advance. I found a solution, but I doubt that it is optimal.
Background: I wrote Groovy code that parses a domain-specific language. The parsing code is statically compiled and included in a Java application. In the parser implementation, I have classes acting as delegates for specific DSL sections. These classes are called using the following pattern:
class DslDelegate {
private Configuration configuration
def section(@DelegatesTo(SectionDelegate) Closure cl) {
cl.delegate = new SectionDelegate(configuration)
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
}
}
I want to call such a method directly from Java code. I can create a new object DslDelegateand then call the method section(). However, I need to create and pass an argument that is an instance Closure. I want the content to be initialized from the object String.
My solution: The following Java code (utility) works, but I ask for improvements. Of course, can this be done in a cleaner or more efficient way?
public Closure<?> buildClosure(String... strings) throws IOException {
Closure<?> closure = null;
StringBuilder sb = new StringBuilder("def closure() { { script -> ");
sb.append(String.join("\n", strings));
sb.append(" } }");
GroovyClassLoader loader = new GroovyClassLoader();
Class<?> groovyClass = loader.parseClass(sb.toString());
try {
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
closure = (Closure<?>) groovyObject.invokeMethod("closure", null);
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
} finally {
loader.close();
}
return closure;
}
source
share