Tuesday, May 10, 2011

Create Groovy closure programmatically

Groovy integrates with Java quite well. One example is to cast a Groovy closure as a Java interface. This allows us to call Java code from Groovy quite easily. But wait, as Groovy is becoming popular and there is more and more Groovy code, what if I need to call Groovy from inside Java? In particular, when a Groovy closure is expected, how do I create that closure programmatically inside Java?

Does this sound a bit academically? Maybe... But there are actually situations when this is needed. One scenario I run into is related to the dynamic programming of a Groovy script. Groovy allows you to resolve a missing method inside a Groovy script against the script binding. As you probably have guessed, the missing method is expected to a Closure.

This turns out easier than I thought. After poking around the generated closure classes, it occurs to me that while closure is quite special in Groovy, it is still just a type from Java perspective. As a result, we can just code (duh :) the class.  Make sure to include the constructor and doCall method.

Here is the example:

DemoBinding.java
public class DemoBinding extends Binding {
    @Override
    public Object getVariable(String name) {
        return "foo".equals(name) ?
            new FooClosure(this, this) :
            super.getVariable(name);
    }


    class FooClosure extends Closure {
        public FooClosure(Object owner, Object thisObject) {
               super(owner, thisObject);
               parameterTypes = new Class[1];
               parameterTypes[0] = String.class;
               maximumNumberOfParameters = 1;
          }


        public java.lang.Object doCall(String message) {
             System.out.println(message);
             return Closure.DONE;
        }
    }
}


DemoScript.groovy
foo "Hello world"

Tester.groovy
Script script = new DemoScript()
script.setBinding (new DemoBinding())
script.run()





No comments: