tags:

views:

89

answers:

3

How do you call a function defined in a Groovy script file from Java?

Example groovy script:

def hello_world() {
   println "Hello, world!"
}

I've looked at the GroovyShell, GroovyClassLoader, and GroovyScriptEngine.

+3  A: 

Either

  1. Compile as ataylor suggests
  2. Use JSR-223 as explained here
  3. If you are using Spring, have a groovy class that implements a Java interface, and inject into your code with:

<lang:groovy id="messenger" script-source="classpath:Messenger.groovy">
    <lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>

One advantage of the spring approach is the concept of 'refreshable beans'. That is, Spring can be configured to monitor your script file for modifications, and replace at runtime.

toolkit
+1  A: 

The simplest way is to compile the script into a java class file and just call it directly. Example:

// Script.groovy
def hello_world() {
    println "Hello, World!"
}

// Main.java
public class Main {
    public static void main(String[] args) {
        Script script = new Script();
        script.hello_world();
    }
}

$ groovyc Script.groovy
$ javac -classpath .:$GROOVY_HOME/embeddable/groovy-all-1.7.5.jar Main.java
$ java -classpath .:$GROOVY_HOME/embeddable/groovy-all-1.7.5.jar Main
Hello, World!
ataylor
+3  A: 

Assuming you have a file called test.groovy, which contains (as in your example):

def hello_world() {
   println "Hello, world!"
}

Then you can create a file Runner.java like this:

import groovy.lang.GroovyShell ;
import groovy.lang.GroovyClassLoader ;
import groovy.util.GroovyScriptEngine ;
import java.io.File ;

class Runner {
  static void runWithGroovyShell() throws Exception {
    new GroovyShell().parse( new File( "test.groovy" ) ).invokeMethod( "hello_world", null ) ;
  }

  static void runWithGroovyClassLoader() throws Exception {
    // Declaring a class to conform to a java interface class would get rid of
    // a lot of the reflection here
    Class scriptClass = new GroovyClassLoader().parseClass( new File( "test.groovy" ) ) ;
    Object scriptInstance = scriptClass.newInstance() ;
    scriptClass.getDeclaredMethod( "hello_world", new Class[] {} ).invoke( scriptInstance, new Object[] {} ) ;
  }

  static void runWithGroovyScriptEngine() throws Exception {
    // Declaring a class to conform to a java interface class would get rid of
    // a lot of the reflection here
    Class scriptClass = new GroovyScriptEngine( "." ).loadScriptByName( "test.groovy" ) ;
    Object scriptInstance = scriptClass.newInstance() ;
    scriptClass.getDeclaredMethod( "hello_world", new Class[] {} ).invoke( scriptInstance, new Object[] {} ) ;
  }

  public static void main( String[] args ) throws Exception {
    runWithGroovyShell() ;
    runWithGroovyClassLoader() ;
    runWithGroovyScriptEngine() ;
  }
}

compile it with:

$ javac -cp groovy-all-1.7.5.jar Runner.java 
Note: Runner.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

(Note: The warnings are left as an exercise to the reader) ;-)

Then, you can run this Runner.class with:

$ java -cp .:groovy-all-1.7.5.jar Runner
Hello, world!
Hello, world!
Hello, world!
tim_yates