3

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.

2
  • Why not just var test = new java.util.ArrayList();? Commented Jul 11, 2013 at 11:36
  • @Andremoniy I am looking for a way to add more properties to the Java object. Commented Jul 11, 2013 at 11:38

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

new NativeObject() is not exactly the same as doing {} in JS. What is missing is its default prototype Object. Consider this: NativeObject prototype = new NativeObject(); prototype.setPrototype(ScriptableObject.getObjectPrototype(scope)); sret.setPrototype(prototype); The difference is for example: the NativeObject without prototype does not have the default toString() implementation. So trying to print it somewhere will cause an error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.