4

Although it's not standard practice, I'm curious if it's possible to inject methods into a GroovyShell compilation context.

The idea is to have something like (in Java):

GroovyShell shell = new GroovyShell();
Script script = shell.parse("test()");
script.run();

Where I'd like to dynamically add methods that are invokable, where test() has been listed.

I've experimented a bit with messing with the Script metaClass, but I don't see a way to actually manipulate the metaClass from Java. In particular, calling script.getMetaClass().getMethods().add(...) throws an UnsupportedOperationException.

In essence, I'd like to define DSL call-points that invoke Java methods rather than Groovy-based ones. I'm willing to write this part in Groovy (and am aware of how to do this), but I'm genuinely curious if this is a viable alternative approach, or if it's not, what the pitfalls are.

In short: how can I dynamically define a method that GroovyShell knows about?

2 Answers 2

6

There are two very simple solutions to this: a) the typical "scripting" approach b) the more groovy-ish approach

a) is simply prepending your script-String with a String that defines your methods. b) is putting a reference into the binding, e.g. under the name "test". The value of that reference is a Closure object or any other object that has a "call(args)" method. When while executing the Script, Groovy sees "test()", it will first try to find such a method and if no such method is there it tries to resolve "test" as a property and will find it in the binding. Then it will call the so resolved reference (closure) with the provided arguments (if any).

There are even more advanced options like providing a CompilerConfiguration, which are all listed in the DSL chapter of "Groovy in Action, 2nd edition" (shameless plug).

Sign up to request clarification or add additional context in comments.

2 Comments

Hi I too am stuck in a similar issue.Have posted here: stackoverflow.com/questions/27315115/groovy-dsl-with-java but am still posting this comment here putting forth the issue am stuck with in the hope that you would offer some help. I want to pass a (Java) class-name and its method name in the DSL. And i want to have an instance created for that class and the given method invoked from Groovy. But since am getting the class passed as "class xx.class-name" am unable to create its instance and do the required method invocation. Could you please provide a little guidance here? Thanks.
From Java one can do binding.setProperty("desiredMethodName", new MethodClosure(myObject, "myMethod"));. The only issue is that existing methods cannot be overwritten. Thanks for pointing out this option.
0

I search examples with MethodClosure without luck. This worked for me:

Closure whoami = new Closure(this){
  @Override
  public Object call(Object... args) {
    //add custom logic here or read passed args
    return "javatar";
  }
};
Binding b = new Binding();
b.setVariable("whoami", whoami);

After that, I can use whoami as method in my groovy script

whoami()

If it is a simple method, I prefer to use the option A of Dierk:

simply prepending your script-String with a String that defines your methods.

But if it is complex, I use Closure :D

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.