This is the 26th day of my participation in the August Text Challenge.More challenges in August

Java Scripting API support

In Section 6.3 we saw how to call Java functions in AviatorScript. Here we will show you how to call functions in AviatorScript using the scripting API provided by Java, etc.

AviatorScript with built-in support for * * * * Java Scripting API, and provides a AviatorScriptEngineFactory SPI implementation, As long as your classpath contains a jar reference to aviator, you can use it directly. Let’s look at some examples (all of the sample code is in the source example scripting directory).

Obtaining the Execution Engine

AviatorScript execution engine can be obtained by ScriptEngineManager:

package com.googlecode.aviator.example.scripting; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class ScriptEngineExample { public static void main(final String[] args) { final ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine engine = sem.getEngineByName("AviatorScript"); }}Copy the code

We’ll use this engine for various examples.

Configuring the Execution Engine

You can get the underlying AviatorEvaluatorInstance reference from ScriptEngine to configure the engine:

package com.googlecode.aviator.example.scripting; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import com.googlecode.aviator.AviatorEvaluatorInstance; import com.googlecode.aviator.Feature; import com.googlecode.aviator.Options; import com.googlecode.aviator.script.AviatorScriptEngine; public class ConfigureEngine { public static void main(final String[] args) throws Exception { final ScriptEngineManager  sem = new ScriptEngineManager(); ScriptEngine engine = sem.getEngineByName("AviatorScript"); AviatorEvaluatorInstance instance = ((AviatorScriptEngine) engine).getEngine(); // Use compatible feature set instance.setOption(Options.FEATURE_SET, Feature.getCompatibleFeatures()); // Doesn't support if in compatible feature set mode. engine.eval("if(true) { println('support if'); } "); }}Copy the code

The default engine is in the following mode:

  1. Full syntax feature support
  2. Cache compilation mode
  1. Enable reflection – based Java method calls

evaluation

At its simplest, you can simply execute an AviatorScript script by calling the eval(script) method

package com.googlecode.aviator.example.scripting; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class EvalScriptExample { public static void main(final String[] args) throws Exception { final ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine engine = sem.getEngineByName("AviatorScript"); engine.eval("print('Hello, World')"); }}Copy the code

This will print Hello World to the console, call print,

If your script is a file, you can also use eval(reader) :

import javax.script.*; public class EvalFile { public static void main(String[] args) throws Exception { // create a script engine manager ScriptEngineManager factory = new ScriptEngineManager(); // create AviatorScript engine ScriptEngine engine = factory.getEngineByName("AviatorScript"); // evaluate AviatorScript code from given file - specified by first argument engine.eval(new java.io.FileReader(args[0])); }}Copy the code

The file name is specified by the first argument executed.

The default engine is in cache expression mode.

Injecting variable

You can inject global variables into the script and execute:

package com.googlecode.aviator.example.scripting; import java.io.File; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class ScriptVars { public static void main(final String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("AviatorScript"); File f = new File("test.txt"); // expose File object as variable to script engine.put("file", f); // evaluate a script string. The script accesses "file" // variable and calls method on it engine.eval("print(getAbsolutePath(file))"); }}Copy the code

Here we inject the file f as a global variable through the engine.put method, and then execute the script print(getAbsolutePath(file)) to print the absolute path to the file.

The default engine enables Java reflection based method invocation patterns.

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.