Getting started with the Java script engine

Keywords: Programming Java Javascript ECMAScript

Java Script Engine

The Java script engine can embed scripts into Java code, customize and extend Java applications, and since the introduction of JDK1.6, based on the Rhino engine, uses the Nashorn engine after JDK1.8 to support ECMAScript 5, but may change later.

The script engine packages are located in javax.script, and the class names and descriptions are as follows

Interface

  • Bindings

    key-value pair mapping, all keys are String

  • Compilable

    Implemented by a specific script engine for compiling scripts and reusable.

  • Invocable is implemented by a specific script engine that allows calls to scripts previously executed

  • ScriptContext

    Script Engine Context for binding applications to script engines

  • ScriptEngine

    Implemented by a specific script engine, which defines how to execute scripts, key-value pair mapping relationships, and script engine context

  • ScriptEngineFactory

    A script engine factory, where each script engine has a corresponding factory.ScriptEngineManager retrieves all ScriptEngineFactories instances from ClassLoader

class

  • AbstractScriptEngine

    An Abstract implementation class of ScriptEngine that provides a standard implementation of ScriptEngine

  • CompiledScript

    Extended by a class that stores compiled results.They can be stored as Java classes, Java class files, or script opcodes, and they can be executed repeatedly without having to be re-parsed.Each CompiledScript is associated with a ScriptEngine, and calling the eval method of CompiledScript causes the ScriptEngine to execute

  • ScriptEngineManager

    Script Engine Manager, which provides instantiation mechanisms for ScriptEngine and maintains a collection of key/value pairs for use by all created ScriptEngine shares

  • SimpleBindings

    A simple key-value mapping using HashMap or other Maps

  • SimpleScriptContext

    A simple implementation of ScriptContext

abnormal

  • ScriptException

    Generic exception class for scripting API, exception class thrown with file name, line number, column number information

Example

Ordinary

@Test
public void scriptTest() throws ScriptException {
    ScriptEngineManager engineManager = new ScriptEngineManager();
    //Get the JavaScript parsing engine
    ScriptEngine engine = engineManager.getEngineByName("JavaScript");
    //Map the x variable to Hello World!
    engine.put("x", "Hello World!");
    engine.eval("print(x)");
}
//output
//Hello World!

More complex

Read script from file

/**
     * Read Js scripts from files
     * test.js Contents in:
     * var obj = new Object();
     * obj.hello = function (name) {
     *     print('Hello, ' + name);
     * }
     * @throws Exception
     */
@Test
public void file() throws Exception{
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    engine.eval(new FileReader(new File("script/test.js")));
    Invocable inv = (Invocable) engine;
    Object obj = engine.get("obj");
    inv.invokeMethod(obj, "hello", "Script Test!" );
}

Injecting Java variables into scripts

There may be a need to use Java variables in scripts

@Test
public void scriptVar() throws Exception{
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    File file = new File("F:/test/test.txt");
    //File object f is injected directly into the js script and can be used as a global variable
    engine.put("files", file);
    engine.eval("print(files.getPath());print(files.getName());");
}

Call methods in scripts

Calling methods in loaded scripts using Invocable

@Test
public void scriptTest1() throws ScriptException, NoSuchMethodException {
    ScriptEngineManager engineManager = new ScriptEngineManager();
    ScriptEngine engine = engineManager.getEngineByName("JavaScript");

    StringBuilder sb = new StringBuilder();
    sb.append("var obj = new Object();");
    sb.append("obj.hello = function(name){print('Hello, ' + name);}");
    engine.eval(sb.toString());

    //Invocable can call scripts that have already been loaded
    Invocable invocable = (Invocable) engine;
    //Get the obj object of the script
    Object object = engine.get("obj");
    //Calling the hello function of an obj object
    invocable.invokeMethod(object, "hello", "Script Method!");
}
//output
//Hello, Script Method!

Multiple Scopes

One script engine, multiple scope s, x variables do not overwrite previous variables

@Test
public void scriptTest() throws ScriptException {
    ScriptEngineManager engineManager = new ScriptEngineManager();
    ScriptEngine engine = engineManager.getEngineByName("JavaScript");
    engine.put("x", "Hello World!");
    engine.eval("print(x)");


    ScriptContext context = new SimpleScriptContext();
    //New Script context Binds ENGINE_SCOPE of ScriptContext
    Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);

    // Add a new variable to the new range engineScope
    bindings.put("x", "word hello!!");
    // Execute the same script - but this time pass in a different script context
    engine.eval("print(x);", bindings);
    engine.eval("print(x);");
}

//output
//Hello World!
//word hello!!
//Hello World!

Using scripts to implement Java interfaces

@Test
public void runnableImpl() throws Exception{
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");

    // Define a JavaScript code script in a String
    String script = "function run() { print('run called'); }";
    // Execute this script
    engine.eval(script);

    // Gets the Runnable interface object (instance) from the script engine. The interface method is implemented by a script function with a matching name.
    Invocable inv = (Invocable) engine;
    // In the script above, we have implemented the run() method of the Runnable interface
    Runnable runnable = inv.getInterface(Runnable.class);

    // Start a thread to run the script script above that implements the runnable interface
    Thread thread = new Thread(runnable);
    thread.start();
    Thread.sleep(1000);
}

If the script is object-based, the Java interface can be implemented by executing the script to avoid calling the script's global functions.

@Test
public void runnableObject() throws ScriptException {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");

    String script = "var obj = new Object();obj.run = function() {println('run method called')}";
    engine.eval(script);

    //Get script objects
    Object object = engine.get("obj");
    Invocable invocable = (Invocable) engine;
    Runnable runnable = invocable.getInterface(object, Runnable.class);

    Thread thread = new Thread(runnable);
    thread.start();
    Thread.sleep(1000);
}

Posted by gabeg on Mon, 09 Dec 2019 06:27:58 -0800