graalvmgraaljs

GraalJs - call constructor of java object


I want to use graal js to provide some scripting extension to my application

How can i initialize a new java object on the javascript side?

Context ctx = Context ctx = Context.newBuilder().allowHostAccess(HostAccess.ALL).allowAllAccess(true).build().create();
Value binding = ctx.getBindings("js");
binding.putMember("ArrayList", ArrayList.class);
ctx.eval("js","let list = new ArrayList();list.add(\"1\")");
List list = binding.getMember("list").as(List.class);
assert list.size() == 1;

following code throws exception

Exception in thread "main" TypeError: instantiate on JavaClass[java.util.ArrayList] failed due to: Message not supported.
    at <js> :program(Unnamed:1:13-27)
    at org.graalvm.polyglot.Context.eval(Context.java:371)

Running graalvm-ce-java11 19.3.2


Solution

  • You need to use Java.type.

    Here is an example taken from https://www.graalvm.org/docs/reference-manual/polyglot/

    var array = new (Java.type("int[]"))(4);
    array[2] = 42;
    console.log(array[2])
    

    Here is a fully runnable example tested with GraalVM 20.0.0

    import org.graalvm.polyglot.*;
    
    class M {
        public static void main(String[] args) {
            try (Context context = Context.newBuilder().allowAllAccess(true).build()) {
                java.util.ArrayList v = context.eval("js",
                "var ArrayList = Java.type('java.util.ArrayList');" +
                "var list = new ArrayList();" + 
                "list.add(1); list").asHostObject();
                System.out.println(v.get(0));
                assert v.get(0).equals(1);
            }
        }
    }
    

    Run with

    graalvm-ce-java8-20.0.0/bin/javac M.java 
    graalvm-ce-java8-20.0.0/bin/java -ea M
    

    To get 1 as output.