ScriptObjectMirrors

A. Sundararajan sundararajan.athijegannathan at oracle.com
Thu Oct 16 13:44:21 UTC 2014


There were many questions in this list and elsewhere on 
ScriptObjectMirror. This email is to clarify those.

Nashorn represents JavaScript objects as instances of implementation 
class called jdk.nashorn.internal.runtime.ScriptObject or one of it's 
subclasses (like NativeArray, NativeRegExp etc. - or even generated ones 
like jdk.nashorn.internal.scripts.JO4 etc)

When ScriptObjects are returned from a script function or evaluated 
script code, ScriptEngine.eval returns an instanceof 
jdk.nashorn.api.scripting.ScriptObjectMirror.

http://cr.openjdk.java.net/~sundar/jdk.nashorn.api/9/javadoc/jdk/nashorn/api/scripting/ScriptObjectMirror.html

Example:

     ScriptEngine e = new ScriptEngineManager().getEngineByName("nashorn");
     Object obj = e.eval("var obj = { foo: 23 }"); // obj is an instance 
of ScriptObjectMirror

Caller can cast the result to ScriptObjectMirror to access properties of 
that script object or call methods on it. All javax.script interface 
methods returning Object (ScriptEngine.eval, Invocable.invokeFunction, 
Invocable.invokeMethod) return ScriptObjectMirror if underlying script 
or script function/method returns a JS object.

But, if you call any Java method accepting Object type param or assign 
to element of Object[], then Nashorn was not wrapping ScriptObject in 
the past. i.e., 'raw' ScriptObject (or subclass) instances "escaped" to 
Java layer. If you try to cast those to ScriptObjectMirror from Java 
code, you got ClassCastException. Also, if you passed such raw object as 
"self" parameter for Invocable.invokeMethod, you would  
IllegalArgumentException. This was causing a lot of confusion - script 
objects got to java code sometimes as wrapped mirror objects and 
sometimes as 'raw' objects!

With a recent change

     http://hg.openjdk.java.net/jdk9/dev/nashorn/rev/a8d44c7c2ac0

in jdk9 and the corresponding backport to jdk8u-dev

http://hg.openjdk.java.net/jdk8u/jdk8u-dev/nashorn/rev/a35c8136c045

the way nashorn wraps internal ScriptObjects to ScriptObjectMirror has 
changed. Script objects are always wrapped to ScriptObjectMirror - even 
when you're calling Java method that accepts "Object" type value. Also, 
return values from java methods returning Object are "unwrapped" (if the 
return value is a ScriptObjectMirror) when it gets to script execution.

Example:

     // list gets ScriptObjectMirror as element
     engine.eval("var m = new java.util.HashMap(); l.put('myobj', { foo: 
33 });");
     engine.eval("var obj = m.get('myobj'); // obj gets unwrapped as 
ScriptObject here");

With this change, raw ScriptObjects don't escape to Java layer at all.

Hope this helps,
-Sundar


More information about the nashorn-dev mailing list