Groovy learning -- running groovy script embedded in JAVA

Keywords: Programming shell Java Javascript Session

Recently, a data statistics system has been designed. There are hundreds of data statistics dimensions in the system, and the indicators of these data statistics may be adjusted at any time. If the API design of data statistics is implemented one by one based on Java coding, the workload is large and the maintenance cost is high. Finally, it is determined to separate the calculation part of "data statistics" into a script file (javascript, or Groovy), It is very convenient to realize the decoupling of "data statistics Task" and "data statistics rules (calculation)", and the ability of dynamic loading and running. By the way, make a note of Java embedded running Groovy script

There are three kinds of common class support for running Groovy in Java: GroovyShell,GroovyClassLoader and java script engine (JSR-223)

  • 1) GroovyShell: usually used to run "script fragments" or some scattered expressions

  • 2) GroovyClassLoader: if the script is a complete file, especially when there are API types, such as JAVA like interfaces, GroovyClassLoader is usually used in object-oriented design

  • 3) ScriptEngine: JSR-223 should be a recommended use strategy. It is standardized and simple

1, Sample GroovyShell code

1.1 simple expression execution, method call_

/** 
 * Short answer script execution 
 * @throws Exception 
 */  
public static void evalScriptText() throws Exception{  
    //groovy.lang.Binding  
    Binding binding = new Binding();  
    GroovyShell shell = new GroovyShell(binding);  
      
    binding.setVariable("name", "zhangsan");  
    shell.evaluate("println 'Hello World! I am ' + name;");  
    //In script, declare variables, do not use def, otherwise the shape is inconsistent  
    shell.evaluate("date = new Date();");  
    Date date = (Date)binding.getVariable("date");  
    System.out.println("Date:" + date.getTime());  
    //Get the value of script internal variable or execute the result by return value  
    //In a shell instance, all variable values will be passed in this "session". The "date" can be obtained in the script after that  
    Long time = (Long)shell.evaluate("def time = date.getTime(); return time;");  
    System.out.println("Time:" + time);  
    binding.setVariable("list", new String[]{"A","B","C"});  
    //invoke method  
    String joinString = (String)shell.evaluate("def call(){return list.join(' - ')};call();");  
    System.out.println("Array join:" + joinString);  
    shell = null;  
    binding = null;  
}

1.2 pseudo main method execution_

/** 
 * When the groovy script is a complete class structure, you can start the script by executing the main method and passing parameters 
 */  
public static void evalScriptAsMainMethod(){  
    String[] args = new String[]{"Zhangsan","10"};//main(String[] args)  
    Binding binding = new Binding(args);  
    GroovyShell shell = new GroovyShell(binding);  
    shell.evaluate("static void main(String[] args){ if(args.length != 2) return;println('Hello,I am ' + args[0] + ',age ' + args[1])}");  
    shell = null;  
    binding = null;  
}

1.3 running Groovy script with class structure through Shell_

/** 
 * Run full script 
 * @throws Exception 
 */  
public static void evalScriptTextFull() throws Exception{  
    StringBuffer buffer = new StringBuffer();  
    //define API  
    buffer.append("class User{")  
            .append("String name;Integer age;")  
            //.append("User(String name,Integer age){this.name = name;this.age = age};")  
            .append("String sayHello(){return 'Hello,I am ' + name + ',age ' + age;}}\n");  
    //Usage  
    buffer.append("def user = new User(name:'zhangsan',age:1);")  
            .append("user.sayHello();");  
    //groovy.lang.Binding  
    Binding binding = new Binding();  
    GroovyShell shell = new GroovyShell(binding);  
    String message = (String)shell.evaluate(buffer.toString());  
    System.out.println(message);  
    //Override main method, default execution  
    String mainMethod = "static void main(String[] args){def user = new User(name:'lisi',age:12);print(user.sayHello());}";  
    shell.evaluate(mainMethod);  
    shell = null;  
}

1.4 method execution and partial call_

/** 
     * Run scripts in a process oriented manner 
     * @throws Exception 
     */  
    public static void evalScript() throws Exception{  
        Binding binding = new Binding();  
        GroovyShell shell = new GroovyShell(binding);  
        //Direct method call  
        //shell.parse(new File(//))  
        Script script = shell.parse("def join(String[] list) {return list.join('--');}");  
        String joinString = (String)script.invokeMethod("join", new String[]{"A1","B2","C3"});  
        System.out.println(joinString);  
        ////Script can be in any format, main method or common method  
        //1) def call(){...};call();  
        //2) call(){...};  
        script = shell.parse("static void main(String[] args){i = i * 2;}");  
        script.setProperty("i", new Integer(10));  
        script.run();//function,  
        System.out.println(script.getProperty("i"));  
        //the same as  
        System.out.println(script.getBinding().getVariable("i"));  
        script = null;  
        shell = null;  
    }

2, GroovyClassLoader code example_

2.1 parsing groovy files_

/** 
     * from source file of *.groovy 
     */  
    public static void parse() throws Exception{  
        GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());  
        File sourceFile = new File("D:\\TestGroovy.groovy");  
        Class testGroovyClass = classLoader.parseClass(new GroovyCodeSource(sourceFile));  
        GroovyObject instance = (GroovyObject)testGroovyClass.newInstance();//proxy  
        Long time = (Long)instance.invokeMethod("getTime", new Date());  
        System.out.println(time);  
        Date date = (Date)instance.invokeMethod("getDate", time);  
        System.out.println(date.getTime());  
        //here  
        instance = null;  
        testGroovyClass = null;  
    }

2.2 how to load compiled groovy files (. class)_

public static void load() throws Exception {  
        GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());  
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\TestGroovy.class"));  
        ByteArrayOutputStream bos = new ByteArrayOutputStream();  
        for(;;){  
            int i = bis.read();  
            if( i == -1){  
                break;  
            }  
            bos.write(i);  
        }  
        Class testGroovyClass = classLoader.defineClass(null, bos.toByteArray());  
        //instance of proxy-class  
        //if interface API is in the classpath,you can do such as:  
        //MyObject instance = (MyObject)testGroovyClass.newInstance()  
        GroovyObject instance = (GroovyObject)testGroovyClass.newInstance();  
        Long time = (Long)instance.invokeMethod("getTime", new Date());  
        System.out.println(time);  
        Date date = (Date)instance.invokeMethod("getDate", time);  
        System.out.println(date.getTime());  
          
        //here  
    bis.close();  
        bos.close();  
        instance = null;  
        testGroovyClass = null;  
    }

3, ScriptEngine

3.1 pom.xml dependency_

<dependency>  
    <groupId>org.codehaus.groovy</groupId>  
    <artifactId>groovy</artifactId>  
    <version>2.1.6</version>  
</dependency>  
<dependency>  
    <groupId>org.codehaus.groovy</groupId>  
    <artifactId>groovy-jsr223</artifactId>  
    <version>2.1.6</version>  
</dependency>

3.2 code example_

public static void evalScript() throws Exception{  
    ScriptEngineManager factory = new ScriptEngineManager();  
    //Generate one engine instance at a time  
    ScriptEngine engine = factory.getEngineByName("groovy");  
    System.out.println(engine.toString());  
    assert engine != null;  
    //javax.script.Bindings  
    Bindings binding = engine.createBindings();  
    binding.put("date", new Date());  
    //If the script text comes from a file, get the contents of the file first  
    engine.eval("def getTime(){return date.getTime();}",binding);  
    engine.eval("def sayHello(name,age){return 'Hello,I am ' + name + ',age' + age;}");  
    Long time = (Long)((Invocable)engine).invokeFunction("getTime", null);  
    System.out.println(time);  
    String message = (String)((Invocable)engine).invokeFunction("sayHello", "zhangsan",new Integer(12));  
    System.out.println(message);  
}

It should be noted that ${expression} will be considered as a variable in groovy. If the "$" symbol needs to be output, it needs to be escaped to "\ $"

For more information about ScriptEngine, please reference resources.

Posted by djroki on Wed, 13 May 2020 02:16:26 -0700