Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top