Attila,

Please see below

On 10/12/13 13:41, Attila Szegedi wrote:
On Dec 10, 2013, at 2:19 PM, Tim Fox <[email protected]> wrote:

I did a bit more digging here and inspected (in Java) the classes of objects 
passed from JavaScript into Java in the following two cases:

1) Objects explicitly passed from JavaScript to Java, e.g. in a script:

someJavaObject.callJavaMethod(..);

2) Objects passed to Java from JavaScript by returning them from the execution 
of a script, i.e. the last statement of a script which is returned to Java via 
the return value of engine.eval(...)

It seems that objects passed to Java code via 1) do not implement 
jdk.nashorn.api.scripting.ScriptObjectMirror but objects passed in 2) do 
implement jdk.nashorn.api.scripting.ScriptObjectMirror

So, it seems that I can workaround the issue by not explicitly passing objects 
from JS to Java but returning them from the execution of the script.

I have to say that the current behaviour seems a bit inconsistent to me, 
shouldn't all objects passed to Java from JS be wrapped in ScriptObjectMirror 
to ensure the correct scope is used whenever they are executed?
During execution of the script, invoking a Java method that declares its parameter as "Object" will 
not cause wrapping as we don't want to mess with object identity if we don't have to. If the parameter were 
declared as "JSObject" or "ScriptObjectMirror" (or, as a matter of fact, java.util.Map or 
javax.script.Bindings, as ScriptObjectMirror implements these as well), then you'd get a mirror wrapping the 
actual object.


I tried this technique and it seems to work in most cases. However if the object I pass from JS into Java is itself a Java static class, it fails with this exception:

java.lang.ClassCastException: Cannot cast jdk.internal.dynalink.beans.StaticClass to jdk.nashorn.api.scripting.ScriptObjectMirror at sun.invoke.util.ValueConversions.newClassCastException(ValueConversions.java:461) at sun.invoke.util.ValueConversions.castReference(ValueConversions.java:456)
    at jdk.nashorn.internal.scripts.Script$\^eval\_.runScript(<eval>:7)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:498) at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:207) at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:378) at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:544) at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:526) at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:522) at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:193)

This is demonstrated in this example: https://gist.github.com/purplefox/7892144






Wrapping when coming out of the javax.script API is a matter of exposing 
something that can then further be manipulated as a Bindings object, I think. 
In principle, we maybe could choose not to do that (I'll defer to Sundar as he 
has a better grasp of our javax.script design decisions…)


I'm not sure why some objects passed to Java are wrapped and others aren't...

I'm also concerned about the case of callbacks. Let's say I have a Java object 
which allows a handler to be set:

class MyObject {

  private Runnable handler;

  void setHandler(Runnable handler) {
     this.handler = handler;
  }

  void callHandler() {
     handler.run();
  }

}

And I call an instance of this object from inside a JS script:


myJavaObject.setHandler(function() {
   // Will this JS function be called with the correct scope?
});

The object that gets passed to setHandler does not implement 
ScriptObjectMirror, so when the JS handler function is called, can we be sure 
it wil be executed in the correct scope?
Yes. The Java object implementing Runnable will not be a ScriptObjectMirror, but an 
on-the-fly generated custom class implementing Runnable, and it has a field for storing 
the global it was created with, and its code for "public void run()" has a 
try/finally around the function invocation that sets/restores the global for the current 
thread for the duration of the execution of the function, when needed.

HTH,
   Attila.






On 10/12/13 12:41, Tim Fox wrote:
Hi Sundar,

I see you resolved this issue as a non issue here 
https://bugs.openjdk.java.net/browse/JDK-8029604

Unfortunately I am unable to add comments to the bug so I have a few 
questions...

In either mode, Java level Bindings instance backed Java objects as script variables are 
"read only"
Can you elaborate what this means? Do you mean the Java object _reference_ is 
read only? I.e. JavaScript can't replace the global variable with anything 
else. I imagine ensuring that the Java object itself is read-only would be an 
extremely difficult thing to do.

You can get ScriptObjectMirror wrapper of ScriptFunctions and ScriptObjects and 
share/call/use it from anywhere (ScriptObjectMirror takes care of setting right 
nashorn Global object in thread local storage).
It seems like this is what we need to do to implement CommonJS require-like functionality 
as we need to export objects from scopes such that they are callable from different 
scopes. This is essential for implementing any "node-like" functionality using 
Nashorn.

I can't see anything in the javax.script API that mentions ScriptObjectMirror, 
ScriptFunctions or ScriptObjects, so I assume these are in a different API. Is 
this API documented anywhere, and is it a public API? If you could give a 
simple code example of how my simple test program could be adapted using this 
other API, that would be a great help :)

I guess this also implies that what I want to do is impossible using the 
javax.script API?

On 05/12/13 13:55, A. Sundararajan wrote:
Hi,

Please use "tools" category and include scripting/nashorn in your description 
or title or label somewhere.

PS. we are working on getting appropriate category.

Thanks
Sundar

On Thursday 05 December 2013 06:43 PM, Tim Fox wrote:
Thanks I am trying to submit a bug here:

http://bugreport.sun.com/bugreport/submit_intro.do

as directed in the link your provided, but I can't see any category I can file 
it against that seems appropriate for Nashorn...

On 05/12/13 13:00, A. Sundararajan wrote:
Please file a bug using web interface. Process explained in this post by Jim:

http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-December/002515.html

Thanks
-Sundar

On Thursday 05 December 2013 06:14 PM, Tim Fox wrote:
Oops! Forgot to provide a link to the example...

Here it is:

https://gist.github.com/purplefox/7804105

On 05/12/13 12:42, Tim Fox wrote:
Hello Nashorn folks,

I've been playing around with Nashorn today, and in particular I've been trying 
to implement commonJS-like require() functionality, but having some problems. 
Most probably I am doing something stupid...

I'm sure you all know, with commonJS modules you can "require" them from your 
JS scripts, e.g.

var someObject = require("modulename");

Then in modulename.js

you do your stuff then export the object that ends up being returned from the 
require, e.g.

var someObject = {
  foo: "bar"
}

module.exports = someObject;

One key thing is that modules have their own scope, so any globals defined in 
modulename.js shouldn't be visible in the script that requires them, and vice 
versa.

While trying to implement this using Nashorn and running scripts in different 
scopes I've found it's possible for Nashorn to get confused about what scope 
it's using, and for scopes to leak from one to another.

I created this simple runnable example to demonstrate the issue.

I wonder if anyone can advise whether this is a bug, or perhaps I am using the 
API incorrectly. If the latter, could you advise on the proper way to use the 
API to implement this kind of functionality.

Many thanks



Reply via email to