Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Object as prototype in Rhino

I am having difficulties using Java objects as JavaScript prototypes. This illustrates my problem:

var test = {};
test.prototype = new java.util.ArrayList();
test.prototype.add(1); // works
test.add(1);           // fails

It seems to me that this should never happen: any function property accessible on the prototype must be accessible on the object itself.

My goal is to add more function properties to the wrapped Java object. Is there at least a workaround to get the desired effect with Rhino? The constraint is that the adding of properties must be done on the JavaScript side.

My Rhino is 1.7R4.

like image 279
Marko Topolnik Avatar asked Jun 12 '26 16:06

Marko Topolnik


1 Answers

As explained here, the workaround is to set the prototype of the wrapped Java object to new NativeObject(). Note that in the linked thread there was no confirmation from any authority that this is in fact the right thing to do, so it may just happen to work for your use case and break others.

Anyway, the best place to set the prototype on the Java side is in a custom wrapFactory:

cx.setWrapFactory(new WrapFactory() {
  @Override public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType) {
    final Object ret = super.wrap(cx, scope, obj, staticType);
    if (ret instanceof Scriptable) {
      final Scriptable sret = (Scriptable) ret;
      if (sret.getPrototype() == null) sret.setPrototype(new NativeObject());
    }
    return ret;
  }
});

and on the JavaScript side this will now work:

var test = new java.util.ArrayList();
test.x = 'a';

So, compared to your posted attempt, you need to invert the roles of object and prototype.

A funny thing: now you can freely set the prototype on the JavaScript side as well:

test.prototype = {};

This sounds like a Rhino bug to me, or at least a point to improve.

like image 199
Marko Topolnik Avatar answered Jun 14 '26 05:06

Marko Topolnik