JSON.stringify does not support Java class that extends AbstractJSObject

Sundararajan Athijegannathan sundararajan.athijegannathan at oracle.com
Mon Jun 13 03:46:21 UTC 2016


Well, the basic property access/modification, indexed element
access/modification, function call etc. are indeed glued to JSObject
methods. Nashorn includes separate dynalink linker to implement this.
But, a JSObject is *not* a Nashorn ScriptObject in *every* possible
context. This is by design. This applies to Java POJOs as well. Nashorn
tries to give illusion of scriptobject-like behavior for Java POJOs
using dynalink "beans linker".

That said, we have been trying to increase number of places where
JSObjects and ScriptObjects are uniformly treated.  There was a recent fix:

http://hg.openjdk.java.net/jdk9/dev/nashorn/rev/c24beef07d1b
https://bugs.openjdk.java.net/browse/JDK-8157160

And that has been backported to 8u as well.

Thanks,
-Sundar

On 6/10/2016 10:33 PM, Bill Reed wrote:
> I have a Java class ExampleTuple2  that extends AbstractJSObject. My
> ExampleTuple2 has a toJSON method. I instantiate the object in JavaScript
> (nashorn) if I do a JSON.stringify(tuple2Instance) the result "undefined"
>
> The API documentation for AbstractJSObject
> https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/AbstractJSObject.html
> states *"This is the base class for nashorn ScriptObjectMirror class. This
> class can also be subclassed by an arbitrary Java class. Nashorn will treat
> objects of such classes just like nashorn script objects. Usual nashorn
> operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
> to appropriate method call of this class." *
>
> Should my toJSON method be calls when using JSON.stringify for this type of
> object?
>
> Example of the Java code.
>
> package org.eclairjs.nashorn.wrap;
>
> import jdk.nashorn.api.scripting.AbstractJSObject;
>
> import org.eclairjs.nashorn.Utils;
>
> public class ExampleTuple2 extends AbstractJSObject {
>
>     public abstract class WrappedFunction  extends AbstractJSObject {
>
>         @Override
>
>         public boolean isFunction() {
>
>             return true;
>
>         }
>
>     }
>
>     Object _1;
>
>     Object _2;
>
>     public ExampleTuple2(scala.Tuple2 tuple2) {
>
>         _1=Utils.javaToJs(tuple2._1(),null);
>
>         _2=Utils.javaToJs(tuple2._2(),null);
>
>     }
>
>     public ExampleTuple2(Object _1, Object _2)  {
>
>         this._1=_1;
>
>         this._2=_2;
>
>     }
>
>     WrappedFunction  F_toJSON = new WrappedFunction () {
>
>         @Override
>
>         public Object call(Object thiz, Object... args) {
>
>             return "{\"0\":" + _1 + ",\"1\":" + _2 + "}" ;
>
>         }
>
>     };
>
>     WrappedFunction  F_toString = new WrappedFunction () {
>
>         @Override
>
>         public Object call(Object thiz, Object... args) {
>
>             return "(" + _1 + "," + _2 + ")" ;
>
>         }
>
>     };
>
>     WrappedFunction  F_valueOf = new WrappedFunction () {
>
>         @Override
>
>         public Object call(Object thiz, Object... args) {
>
>             return "(" + _1 + "," + _2 + ")";
>
>         }
>
>     };
>
>     WrappedFunction  F_1 = new WrappedFunction () {
>
>         @Override
>
>         public Object call(Object thiz, Object... args) {
>
>             return _1;
>
>         }
>
>     };
>
>     WrappedFunction F_2  = new  WrappedFunction () {
>
>         @Override
>
>         public Object call(Object thiz, Object... args) {
>
>             return _2;
>
>         }
>
>     };
>
>     // get the value of that named property
>
>     @Override
>
>     public Object getMember(String name) {
>
>         switch (name) {
>
>             case "_1": return F_1;
>
>             case "_2": return F_2;
>
>             case "valueOf": return F_valueOf;
>
>             case "toJSON": return F_toJSON;
>
>             case "toString": return F_toString;
>
>         }
>
>         throw new RuntimeException("Tuple2."+name+" is not defined");
>
>     }
>
>     @Override
>
>     public boolean hasMember(String name) {
>
>         switch (name) {
>
>             case "_1":
>
>             case "_2":
>
>             case "valueOf":
>
>             case "toJSON":
>
>             case "toString":
>
>                 return true;
>
>         }
>
>        return super.hasMember(name);
>
>     }
>
> }
>
>
> Example of the JavaScript code.
>
> var Tuple2 = Java.type('org.eclairjs.nashorn.wrap.ExampleTuple2');
>
> var t = new Tuple2("value1", "value2");
>
> print("t1 " + t._1());
>
> print("t " + t);
>
> print(JSON.stringify(t));



More information about the nashorn-dev mailing list