How Java & GraalJs ScriptEngine interact with variables

424 Views Asked by At

Now, I'm trying execute Javascript in Java application via GraalJS. the following is my code:

import javax.script.*;
import java.util.List;
import java.util.Map;

public class ScriptExec {

    public static void main(String[] args) throws ScriptException {
        System.setProperty("polyglot.engine.WarnInterpreterOnly", "false");

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        Bindings bindings = engine.createBindings();

        // variables
        int num = 9;
        String hello = "bye";
        String[] strings = new String[]{"a", "string", "array"};
        List<String> stringList = List.of("a", "string", "list");
        Map<String, Object> kvs = Map.of("a", "b", "object", "...", "map", "container");

        bindings.put("num", num); 
        bindings.put("hello", hello);
        bindings.put("strings", strings);
        bindings.put("stringList", stringList);
        bindings.put("kvs", kvs);

        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
        String js = """
                console.log(num)
                console.log(hello)
                console.log(JSON.stringify(strings))
                console.log(JSON.stringify(stringList))
                console.log(JSON.stringify(kvs))
                for(let str in strings) {
                    console.log('str: ' + str)
                }
                for(let k in kvs) {
                    console.log('key: ' + k)
                }
                """;
        engine.eval(js);
    }
}
  • and the console output is:
9
bye
{}
{}
{}

as you see, only the integer type and String variables are bind successfully.

  • JDK version: 17
  • GraalJS 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>

1. what is going on array, list and map type variables? 2. how to solve this?

1

There are 1 best solutions below

0
谢良基 On

ok, i find the answer from here

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

import javax.script.ScriptException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ScriptExec {

    public static void main(String[] args) throws ScriptException {
        System.setProperty("polyglot.engine.WarnInterpreterOnly", "false");

        // Get a polyglot context for Graal guest languages(here is JavaScript)
        Context context = Context.newBuilder("js")
                .allowAllAccess(true) // if not allow, you still cannot access the array/list/object members
                .build();

        // Variables
        var num = 9;
        var hello = "bye";
        var strings = new String[]{"a", "string", "array"};
        var stringList = List.of("a", "string", "list");
        var kvs = new HashMap<>(Map.of("a", "ok", "object", 1, "container", "..."));

        // Pass java variable to GraalJS polyglot context
        Value bindings = context.getBindings("js");

        bindings.putMember("num", num);
        bindings.putMember("hello", hello);
        bindings.putMember("strings", strings);
        bindings.putMember("stringList", stringList);
        bindings.putMember("kvs", kvs);

        // JavaScript code
        var script = """
                console.log(num)
                console.log(hello)
                console.log(JSON.stringify(strings))
                console.log(JSON.stringify(stringList))
                console.log(JSON.stringify(kvs.toString()))
                for(let index in strings) {
                    console.log("index:", index, ", value:", strings[index])
                }
                for(let k in kvs) {
                    console.log(k)
                }
                """;

        // Evaluate the code
        context.eval("js", script);

        // Release resources
        context.close();
    }
}

the above code, without create a ScriptEngine explicitly. the polyglot context of Graal does the work.

also can create ScriptEngine firstly, then pass the special polyglot context to it. special means host resources access controlling config (allowXXX...).

if something new, post later