Calling a Java function or constructor that takes a param of type Scriptable from JavaScript with a JS array bombs out (attempting to implement ES6 Proxy)

124 views
Skip to first unread message

P

unread,
Nov 5, 2015, 9:59:19 AM11/5/15
to mozilla-rhino
Hi all,

I'm trying to implement ES6 Proxy in Rhino, but running into a snag: when I send in a JavaScript Array from JavaScript into a Java method or constructor that takes a param of type Scriptable, things break down. When sending in a JavaSCript Object instead, things work fine.

I traced this back to NativeJavaObject.coerceTypeImpl: for JSTYPE_OBJECT the code below is invoked at some point, due to which it works:
else if (type.isInstance(value)) {
    return value;
   }

For JSTYPE_JAVA_ARRAY  such code isn't there and I end up in the else:
else {
     reportConversionError(value, type);
    }

My conclusion is that coerceTypeImpl is buggy: it is supposed to do whatever is needed to 'modify the value so that it returns an instance of the requested type, but specifically for JavaScript arrays (NativeArray) there is no check to see if the value passed in is already an instance of the requested type.

As a matter of fact, I wonder if such an instanceof check shouldn't be at the top of the method where there's currently only a generic check if the passed in value is of the same class as the requested type.

This is now stopping me from my attempt to implement Proxies. I can add the instanceof check for arrays or generically at the top of the function and create a PR and if I manage to pull of the Proxy impl also create a PR for that.

Hoping on some guidance,

P

Greg Brail

unread,
Nov 5, 2015, 12:43:09 PM11/5/15
to mozill...@googlegroups.com
That sounds like a reasonable change to coerceTypeImpl to me. However I don't recall ever having to touch that method. It could be because a lot of the internal code in Rhino doesn't call "Context.jsToJava" but relies on lower-level methods of ScriptRuntime, or it just directly casts the class to the object that it needs to be.

If fixing this helps make your code work, then we can certainly run other tests to see what else it might affect. But I'm also curious why this issue is affecting you and hasn't affected other things as well.

Glad to hear that you're looking at Proxies! 

--
You received this message because you are subscribed to the Google Groups "mozilla-rhino" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mozilla-rhin...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Greg Brail | apigee twitter @gbrail @apigee


P

unread,
Nov 26, 2015, 8:38:32 AM11/26/15
to mozilla-rhino
Hi Greg,

Been going at this on and off and ran into 2 issues for which I'd like to have some advice if possible:
  1. The Proxy specification defined an enumerate and an ownKeys handler:
    1: the first is to be called for the following code construct and should return an iterator object: for (var x in myObject) {...)
    2: the second is to be called for the following codes and needs to return an Array:
      - Object.getOwnPropertyNames
      - Object.getOwnPropertySymbols
      - Object.keys
      - Reflect.ownKeys
    The issue is that in Rhino both for (var x in myObject) {...) and Object.keys go through Scriptable.getIds(). Been breaking my head over how to solve this in such a way that not every implementation of Scriptable requires changing, but still make the Proxy work for every instance of Scriptable out there.
  2. A proxy object needs to act as the target object, for example when creating a Proxy with an Array as target, if you then do JSON.stringify(myArrayProxy), you'd expect the result to be a proper JSON array representation. Now, in the JSON implementation of Rhino, there is an explicit check if the object being stringified is an instance of NativeArray. My proxy implementation is not an instance of NativeArray, but extends ScriptableObject and implements Wrapper and Function. I cannot make it (always) extend NativeArray, because then the same issue would arise with f.e. NativeObjects.

    So, how to solve this? I have two options in mind, but in both scenario's I wonder if it doesn't mean going down a rabitshole though... Idea's appreciated
    • Somehow return a different Proxy implementation depending on the type of the target: since a proxy is created with the JavaScript code "new Proxy(target, handler), I wonder if this is possible at all: at least in Java it is not possible to return instances of different types from a constructor. I was wondering if idscriptable might allow me to do such thing, but I'm not sure
    • Modify the entire Rhino codebase to take into account that an object might be an instance of  Proxy and then act accordingly.
Hope I made the challenges clear. Any ideas/advice appreciated,

Paul
Reply all
Reply to author
Forward
0 new messages