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.