Closed KatarinaKulkova closed 4 years ago
Hi @KatarinaKulkova,
The Context
API's Value
class provides the as
method, which can be used to cast a Value
object to some Java type. In your example above, I think you could try using .as(Runnable.class).run()
?
Hello.
Which Value exactly do you think should be cast as Runnable? I tried the following:
cx.getBindings("js").as(Runnable.class).run();
but this gave me the following error when trying to run the code:
java.lang.UnsupportedOperationException: Unsupported operation identifier 'run' and object
'com.oracle.truffle.polyglot.PolyglotLanguageBindings@57302cec'(language: Java, type:
com.oracle.truffle.polyglot.PolyglotMap). Identifier is not executable or instantiable.
I don't think I am using any other Value except for the Bindings.
I am missing a bit of context, so I am not sure I fully understand what the code in your example is trying to achieve, but if I understand correctly your usage of getInterface()
I think that you should be able to achieve the same semantics by using the global object in your script, so e.g., context.eval("js", "this").as(Runnable.class)
or context.eval("js", "globalThis").as(Runnable.class)
should do the same thing as ((Invocable)engine).getInterface(Runnable.class)
I will try to provide some general context. I am currently working on this document: https://github.com/contiki-ng/cooja/blob/63538bbb882ba06a7b8cf97c11ce2fe4d22e4f88/java/org/contikios/cooja/plugins/LogScriptEngine.java
This is a copy of the document before I made any changes. All I did was replace all instances of the engine with the Context API, as I described in my question.
There is a function in the code called activateScript(). It parses the JavaScript code, then calls engine.eval(jsCode)
which I replaced by cx.eval("js", jsCode)
, then there are some calls to engine.put()
which I replaced by calls to cx.getBindings("js").putMember()
. Finally, scriptThread (which is a Thread created at the beginning of the document), is assigned to be a new Thread, with its run function containing the cast to Invocable. This thread is supposed to run the parsed JavaScript. The activateScript function also does some semaphore stuff, but I don't think it is related to the issue I am having.
So I tried
context.eval("js", jsCode).as(Runnable.class).run();
as you suggested, but this resulted in the following error:
java.lang.NullPointerException
at org.contikios.cooja.plugins.LogScriptEngine$4.run(LogScriptEngine.java:328)
at java.base/java.lang.Thread.run(Thread.java:834)
where LogScriptEngine.java:328
is the line where I do context.eval("js", jsCode).as(Runnable.class).run();
I wonder whether the fact that the engine was cast as an Invocable enabled it to run, and so replacing it with the Context API doesn't work? I am not sure about this.
Nevermind, this solved it:
context.eval("js", "this").as(Runnable.class)
Thank you very much.
OK, happy to hear that it worked (and thanks for the context info) -- your call to ((Invocable)engine).getInterface(Runnable.class).run();
essentially looks for a function called run
in your JS global scope and then calls it, which is why context.eval("js", "this").as(Runnable.class).run()
(or using "globalThis"
) should be equivalent
I see. That makes sense. Thank you for clearing that up. It was very helpful.
Hello!
I am working on porting a rather large code base from nashorn to graal.js. The original code was using javax.script.ScriptEngine.
I have decided to replace the ScriptEngine with the polyglot Context API.
I replaced every call to engine.put() with a call to cx.getBindings("js").putMember() and similarly engine.get() with cx.getBindings("js").getMember() like this:
However, there is one place in the code where I cannot get rid of the engine. The engine is cast as an Invocable and runs a Thread in a thread group:
This is the part I would like to change:
Is there a Context equivalent for this? I could not find any documentation regarding Invocables in the Context API. I have, however, read somewhere that it I should use Context to execute JavaScript code when using GraalVM. So my question is, is there a way to change this piece of code, so that it keeps its functionality but I don't have to use the engine anymore and use the Context API instead? If not, what would be a good way to do it?
Thanks.