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