How do I access Java object from a script?

This example demonstrate how you can access Java object from a script. We start by creating the ScriptEngine object. Then we obtain the Bindings object from the engine and set the polyglot.js.allowHostAccess options to true. We do this using the Bindings‘s put(String name, Object value) method.

After that we can put Java object into the script engine by calling the ScriptEngine‘s put(String key, Object value) method. This value can later be read or access by our script. For example, we pass an array of string and a date object for our script to display.

package org.kodejava.script;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.Date;
import java.util.function.Predicate;

public class AccessJavaObjectFromScript {
    public static void main(String[] args) {
        // Creating an array of five colors
        String[] colors = {"White", "Black", "Red", "Green", "Blue"};
        Date now = new Date();

        // Below is our script to read the values of Java array that
        // contains string of colors and also read the date object.
        String script = """
                let index;
                let colors = colorArray;

                for (index in colors) {
                    print(colors[index]);
                }

                print('----------');
                print('Today is ' + date.toString());
                """;

        // Obtain a ScriptEngine instance.
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByExtension("js");
        Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
        bindings.put("polyglot.js.allowHostAccess", true);
        bindings.put("polyglot.js.allowHostClassLookup", (Predicate<String>) s -> true);

        // Place the colors array into the engine using colorArray key. And
        // the date object using the date key.
        engine.put("colorArray", colors);
        engine.put("date", now);

        try {
            engine.eval(script);
            engine.eval("print(date instanceof Java.type('java.util.Date'))");
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
}

Our code will print as follows:

White
Black
Red
Green
Blue
----------
Today is Sun Oct 10 09:32:06 CST 2021
true

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js</artifactId>
        <version>22.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js-scriptengine</artifactId>
        <version>22.3.2</version>
    </dependency>
</dependencies>

Maven Central Maven Central

How do I get a ScriptEngine by language name and version?

This example show you how you can obtain a script engine for a specific language name and specific language version. In the code below we try to obtain script engine instance for ECMAScript version ECMAScript 262 Edition 11.

package org.kodejava.script;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.List;

public class ScriptEngineSearch {
    public static void main(String[] args) {
        String languageName = "ECMAScript";
        String languageVersion = "ECMAScript 262 Edition 11";

        // Creating a ScriptEngineManager and get the list of available
        // engine factories.
        ScriptEngineManager manager = new ScriptEngineManager();
        List<ScriptEngineFactory> factories = manager.getEngineFactories();

        // We obtain a ScriptEngine from the available factories where
        // the language name is "ECMAScript" and the version is
        // "ECMAScript 262 Edition 11". ECMAScript is the standard name
        // for JavaScript programming language.
        //
        // If we found the desired language we then get the ScriptEngine
        // by calling factory's getScriptEngine() method.
        ScriptEngine engine = null;
        for (ScriptEngineFactory factory : factories) {
            String language = factory.getLanguageName();
            String version = factory.getLanguageVersion();

            if (language.equals(languageName)
                    && version.equals(languageVersion)) {
                engine = factory.getScriptEngine();
                break;
            }
        }

        if (engine != null) {
            try {
                engine.eval("print('Hello There')");
            } catch (ScriptException e) {
                e.printStackTrace();
            }
        }
    }
}

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js</artifactId>
        <version>22.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js-scriptengine</artifactId>
        <version>22.3.2</version>
    </dependency>
</dependencies>

Maven Central Maven Central

How do I call a specific function of a script?

This code demonstrate the use of Invocable interface to invoke a specific function of a script. The Invocable.invokeFunction() takes the function name with or without a parameter as the function’s parameter. The parameter value can be passed as a varargs.

package org.kodejava.script;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.script.Invocable;

public class InvokingFunction {
    public static void main(String[] args) {
        String script = """
                function sayHello() {
                   sayHello(null);
                }

                function sayHello(name) {
                   print('Hi there' + ((name == null) ? '!' : ' ' + name + '!'));
                }
                """;

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByExtension("js");

        try {
            engine.eval(script);

            // Convert / cast the engine into invocable engine.
            Invocable invocableEngine = (Invocable) engine;

            // Invoking sayHello function without parameter.
            invocableEngine.invokeFunction("sayHello");

            // Invoking sayHello function with a parameter.
            invocableEngine.invokeFunction("sayHello", "Jude");
        } catch (ScriptException | NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

This will output:

Hi there!
Hi there Jude!

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js</artifactId>
        <version>22.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js-scriptengine</artifactId>
        <version>22.3.2</version>
    </dependency>
</dependencies>

Maven Central Maven Central

How do I evaluate or execute a script file?

This example demonstrated how to evaluate script that stored on a file. As we know that the eval() method can also accept a Reader object we can then read the script file using FileReader and pass it as the parameter to the eval() method of the ScriptEngine for further evaluation.

package org.kodejava.script;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.io.File;
import java.io.Reader;
import java.io.FileReader;
import java.io.FileNotFoundException;

public class EvalScriptFile {
    public static void main(String[] args) {
        // Obtaining ECMAScript / JavaScript ScriptEngine.
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("ECMAScript");

        try {
            // Create an instance of File object that point to our
            // scripting file. An create a FileReader to read the
            // file to be passed to the ScriptEngine.eval() method.
            //
            // The file need to be placed in the same folder with
            // our class so it enable to read it. We can define the
            // full path to the file also to make easier for the
            // Reader to find it.
            File script = new File("helloworld.js");
            Reader reader = new FileReader(script);

            engine.eval(reader);
        } catch (FileNotFoundException | ScriptException e) {
            e.printStackTrace();
        }
    }
}

Our helloworld.js file.

console.log('Hello World');

for (let i = 0; i <= 10; i++) {
    console.log(`i = ${i}`);
}

The output of the code snippet:

Hello World
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js</artifactId>
        <version>22.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js-scriptengine</artifactId>
        <version>22.3.2</version>
    </dependency>
</dependencies>

Maven Central Maven Central

How do I get the supported scripting engine?

package org.kodejava.script;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngineFactory;
import java.util.List;

public class GetSupportedScriptingEngine {
    public static void main(String[] args) {
        // Creating an instance of ScriptEngineManager an get the list
        // of available ScriptEngineFactory.
        ScriptEngineManager manager = new ScriptEngineManager();
        List<ScriptEngineFactory> factories = manager.getEngineFactories();

        for (ScriptEngineFactory factory : factories) {
            System.out.println(
                    "EngineName      = " + factory.getEngineName());
            System.out.println(
                    "EngineVersion   = " + factory.getEngineVersion());
            System.out.println(
                    "LanguageName    = " + factory.getLanguageName());
            System.out.println(
                    "LanguageVersion = " + factory.getLanguageVersion());
            System.out.println(
                    "Extensions      = " + factory.getExtensions());
            System.out.println();

            List<String> names = factory.getNames();
            for (String name : names) {
                System.out.println("Engine Alias = " + name);
            }
        }
    }
}

The code above produces the following information.

EngineName      = Graal.js
EngineVersion   = Development Build
LanguageName    = ECMAScript
LanguageVersion = ECMAScript 262 Edition 11
Extensions      = [js, mjs]

Engine Alias = js
Engine Alias = JS
Engine Alias = JavaScript
Engine Alias = javascript
Engine Alias = ECMAScript
Engine Alias = ecmascript
Engine Alias = Graal.js
Engine Alias = graal.js
Engine Alias = Graal-js
Engine Alias = graal-js
Engine Alias = Graal.JS
Engine Alias = Graal-JS
Engine Alias = GraalJS
Engine Alias = GraalJSPolyglot

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js</artifactId>
        <version>22.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js-scriptengine</artifactId>
        <version>22.3.2</version>
    </dependency>
</dependencies>

Maven Central Maven Central