This is the 24th day of my participation in the August Text Challenge.More challenges in August
Compile the script and execute it
AviatorScript also supports a precompiled mode for the Scripting API
package com.googlecode.aviator.example.scripting;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class CompileScript {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
Compilable compilable = (Compilable) engine;
CompiledScript script = compilable.compile("a + b");
final Bindings bindings = engine.createBindings();
bindings.put("a", 99);
bindings.put("b", 1);
System.out.println(script.eval(bindings));
}
}
Copy the code
We compile the expression A + B into a CompiledScript object, then create an environment binding with createBindings, bind A and B to 99 and 1 respectively, and execute eval(Bindings) to 100.
The default compilation also enables caching expression mode.
Calling script functions
Calling script functions in Java also supports:
package com.googlecode.aviator.example.scripting;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class InvokeScriptFunction {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
// AviatorScript code in a String
String script = "fn hello(name) { print('Hello, ' + name); }";
// evaluate script
engine.eval(script);
// javax.script.Invocable is an optional interface.
// Check whether your script engine implements or not!
// Note that the AviatorScript engine implements Invocable interface.
Invocable inv = (Invocable) engine;
// invoke the global function named "hello"
inv.invokeFunction("hello", "Scripting!!" );
}
}
Copy the code
We define the Hello function in our script, and then use the Invocable interface to call it in Java code and pass in arguments:
Hello, Scripting!!
Copy the code
We can use maps and closures to simulate object-oriented programming in AviatorScript. Similarly, we can call methods on “objects” in AviatorScript in Java code:
package com.googlecode.aviator.example.scripting; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class InvokeScriptMethod { public static void main(final String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("AviatorScript"); // AviatorScript code in a String. This code defines a script object 'obj' // with one method called 'hello'. String script = "let obj = seq.map(); obj.hello = lambda(name) -> print('Hello, ' + name); end;" ; // evaluate script engine.eval(script); // javax.script.Invocable is an optional interface. // Check whether your script engine implements or not! // Note that the AviatorScript engine implements Invocable interface. Invocable inv = (Invocable) engine; // get script object on which we want to call the method Object obj = engine.get("obj"); // invoke the method named "hello" on the script object "obj" inv.invokeMethod(obj, "hello", "Script Method !!" ); }}Copy the code
We define the object obj, which has a method hello(name), which gets the object from engine. Get (“obj”) in Java code, and then calls invokeMethod(obj, method name, Method argument list) to call the object’s methods.
Implement Java interfaces using scripts
We can use AviatorScript to implement an interface in Java, and then convert a function or object method into that interface to use in Java code. For example, we can use AviatorScript to implement the Runnable interface:
package com.googlecode.aviator.example.scripting;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class RunnableImpl {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
// AviatorScript code in a String
String script = "fn run() { println('run called'); }";
// evaluate script
engine.eval(script);
Invocable inv = (Invocable) engine;
// get Runnable interface object from engine. This interface methods
// are implemented by script functions with the matching name.
Runnable r = inv.getInterface(Runnable.class);
// start a new thread that runs the script implemented
// runnable interface
Thread th = new Thread(r);
th.start();
}
}
Copy the code
We implement a run() function in AviatorScript. Then we get an implementation of the Runnable interface from the engine, which automatically calls the defined run function and executes it. Then we use the Runnable instance in the thread:
run called
Copy the code
Not only functions, but also “objects” :
package com.googlecode.aviator.example.scripting; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class RunnableImplObject { public static void main(final String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("AviatorScript"); // AviatorScript code in a String String script = "let obj = seq.map(); obj.run = lambda() -> println('run method called'); end; "; // evaluate script engine.eval(script); // get script object on which we want to implement the interface with Object obj = engine.get("obj"); Invocable inv = (Invocable) engine; // get Runnable interface object from engine. This interface methods // are implemented by script methods of object 'obj' Runnable r = inv.getInterface(obj, Runnable.class); // start a new thread that runs the script implemented // runnable interface Thread th = new Thread(r); th.start(); }}Copy the code
You can turn methods of an object into implementations of a particular interface.
More Scope to support
In the injecting variables section above, we injected global variables. The Scripting API also allows multiple global variable environments to execute simultaneously, isolated from each other, through ScriptContext, which you can think of as a Map similar to Map
:
package com.googlecode.aviator.example.scripting; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.SimpleScriptContext; public class MultiScopes { public static void main(final String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("AviatorScript"); engine.put("x", "hello"); // print global variable "x" engine.eval("println(x);" ); // the above line prints "hello" // Now, pass a different script context ScriptContext newContext = new SimpleScriptContext(); Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); // add new variable "x" to the new engineScope engineScope.put("x", "world"); // execute the same script - but this time pass a different script context engine.eval("println(x);" , newContext); // the above line prints "world" } }Copy the code
In newContext’s engine-level binding we redefined x as the world string and passed it in to eval. The two will print different results:
hello
world
Copy the code