Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append CompiledScript or add two CompiledScript

Hello I'm using Groovy engine to eval a certain script. The problem is that the execution time is a little bit big, so I want to separate my script into two scripts. The first one is static and can be compiled inside @PostConstruct method and the second is a variable and it depends on some parameters that the user chooses. This is what I want to do:

Bindings bindings;
CompiledScript scriptC;
String script1="Static Script";
String script2="Variable Script";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
scriptC = ((Compilable) engine).compile(script1); 
//Execute some instruction to generate 'script2'
scriptC += ((Compilable) engine).compile(script2);//Please note the += operator

or

Bindings bindings;
CompiledScript scriptC;
String script1="Static Script";
String script2="Variable Script";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
scriptC = ((Compilable) engine).compile(script1); 
//Execute some instruction to generate 'script2'
scriptC.append(((Compilable) engine).compile(script2));//Please note the append function

These two code does not work for sure, I used them just to illustrate what I'm attempting to do. Is it possible to combine two scripts into a single one?

like image 284
Mehdi Bouzidi Avatar asked Jun 11 '26 08:06

Mehdi Bouzidi


1 Answers

You can't combine like that two CompiledScript objects. If it comes to Groovy - when Groovy script gets compiled it creates a class that extends groovy.lang.Script with a few methods inside. In this case adding two scripts to each other means merging two Java classes.

Consider evaluating both scripts in separation as an alternative. Take a look at following example:

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

public class ScriptTest {

    public static void main(String[] args) throws ScriptException {
        final ScriptEngineManager manager = new ScriptEngineManager();
        final ScriptEngine engine = manager.getEngineByName("Groovy");

        final Bindings bindings = new SimpleBindings();
        bindings.put("a", 3);

        final String script1 = "println 'Running first script...'; def c = 2; def d = c + a; return d";
        final CompiledScript compiledScript1 = ((Compilable) engine).compile(script1);

        //Execute some instruction to generate 'script2'
        final String script2 = "println 'Running second script...';";
        final CompiledScript compiledScript2 = ((Compilable) engine).compile(script2);

        Integer returnedValue = (Integer) compiledScript1.eval(bindings);
        System.out.println("Returned value from the first script: " + returnedValue);

        if (returnedValue > 1) {
            compiledScript2.eval(bindings);
        }
    }
}

Creating CompiledScript object is one thing. Second thing is evaluation of those scripts. If you always evaluate script1 and script2 right away, then you simply need:

compiledScript1.eval(bindings);
compiledScript2.eval(bindings);

However script1 may return some value and based on that value you can decide if script2 should be evaluated. Let's say script1 returns an Integer and I will evaluate script2 only if returned value is greater than 1:

Integer returnedValue = (Integer) compiledScript1.eval(bindings);
if (returnedValue > 1) {
    compiledScript2.eval(bindings);
}

Alternatively you can base on bindings values after running script1. Let's say script1 modifies bindings a and b and set both to true (assuming they hold boolean type):

compiledScript1.eval(bindings);
if (bindings.get("a") && bindings.get("b")) {
    compiledScript2.eval(bindings);
}

Calling a function defined in script1 from script2

Let's say script1 is defined as follows:

import groovy.json.JsonOutput

def json(Map map) {
    return new JsonOutput().toJson(map)
}

println json([test: 1])

In case you have to call json(map) function inside script2 - you can do it. Take a look at this example:

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

public class ScriptTest {

    public static void main(String[] args) throws ScriptException {
        final ScriptEngineManager manager = new ScriptEngineManager();
        final ScriptEngine engine = manager.getEngineByName("Groovy");

        final Bindings bindings = new SimpleBindings();
        bindings.put("a", 3);

        final String script1 = "import groovy.json.JsonOutput\n" +
                "\n" +
                "def json(Map map) {\n" +
                "    return new JsonOutput().toJson(map)\n" +
                "}\n" +
                "\n" +
                "println json([test: 1])";

        final CompiledScript compiledScript1 = ((Compilable) engine).compile(script1);

        //Execute some instruction to generate 'script2'
        final String script2 = "println 'Running second script...'; println json([test: 2]);";
        final CompiledScript compiledScript2 = ((Compilable) engine).compile(script2);

        compiledScript1.eval(bindings);
        compiledScript2.eval(bindings);
    }
}

script2 is defined as:

println 'Running second script...';
println json([test: 2]);

When you run it you will see in the console:

{"test":1}
Running second script...
{"test":2}

The first two lines come from script1 while the last line is generated by script2. Keep in mind that both CompiledScript hold a reference to the same engine, so you can refer to functions defined in previously evaluated scripts.

like image 187
Szymon Stepniak Avatar answered Jun 13 '26 21:06

Szymon Stepniak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!