1

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

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

That means I have to opt in for nashorn compact mode? No other way around? If so then how can i initialize polyglot context with these options Calling Context.newBuilder().option("experimental-options","true").option("js.nashorn-compat", "true").build().create(); throws java.lang.IllegalArgumentException: Could not find option with name experimental-options.
See my edited comment. I added an example you can run. No nashorn mentioned.
0

You could also use the sj4js library. There you can define constructors which seamlessly blend into JS.

// we create a new JS engine and add
// TestClass as a constructor. This constructor is added to globalThis such that it
// can be called as a costructor.
try (JScriptEngine engine = new JScriptEngine(new JsGlobalThis(),"gt")) {
    engine.addConstructor(new TestClass("empty"));
            
    /* call your js code here */
}

Your JS code than looks like this you would expect it.

// we create a new variable from the constructor
var tc = new TestClass("test");

console.log(tc.name)
// test

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.