Tim – and everyone else interested – this is now implemented. You can try it 
out with both JDK9 EA from <https://jdk9.java.net/download 
<https://jdk9.java.net/download>> or JDK8u60 EA from 
<https://jdk8.java.net/download.html <https://jdk8.java.net/download.html>>

The final name of the API ended up being “Java.asJSONCompatible(obj)” instead 
of “Java.toJSONCompatible(obj)”. It’ll give you back an object that’s a live 
view of the underlying JS object, with most objects being represented as 
Map<String, Object> but JS native Array objects being represented as 
List<Object> instead, obviously applying to transitively retrieved properties 
of the initial object too.

Cheers,
  Attila.

> On Dec 5, 2014, at 2:30 PM, Attila Szegedi <[email protected]> wrote:
> 
> FYI, I filed it as an enhancement request so we don't lose track of it: 
> https://bugs.openjdk.java.net/browse/JDK-8066773
> 
> On Nov 27, 2014, at 8:08 PM, Tim Fox <[email protected]> wrote:
> 
>> On 27/11/14 14:48, Attila Szegedi wrote:
>>> So, some initial discussion of this with my team leads to following 
>>> conclusions:
>>> 
>>> - We can't stop wrapping all objects in ScriptObjectMirror, as 
>>> ScriptObjectMirror is a public class, and we allow people to expect it. If 
>>> we now started returning ScriptObjectMirror sometimes and ArrayMirror 
>>> (provisional name) other times, that'd be an API breaking change. That's 
>>> sad, really – we should've probably never made ScriptObjectMirror public 
>>> and instead forced people to only program against the JSObject interface 
>>> instead.
>>> 
>>> - We've been thinking of creating a separate "class ArrayMirror implements 
>>> JSObject, List<Object>" for wrapping JS Arrays, but you'd need to 
>>> explicitly ask a mirror that'll return these transitively, e.g. we could 
>>> give you a Java.toJSONCompatible(obj) API that you'd use as: 
>>> "myObject.expectsJSON(Java.toJSONCompatible(someJson));" You'd still be 
>>> getting a ScriptObjectMirror on the top level (as long as it ain't an array 
>>> in which case the top level would itself be an ArrayMirror), but it'd be 
>>> carrying a hidden flag that'd change its behavior so whenever you retrieve 
>>> an Array from it, it gets wrapped into ArrayMirror and not 
>>> ScriptObjectMirror. Also, if you retrieve an Object from it, you'd get a 
>>> ScriptObjectMirror with this flag propagated, so Arrays at any nesting 
>>> depth would always be exposed as Lists. Arguably, this could be the default 
>>> behaviour except for the fact that it isn't how it worked since the initial 
>>> 8 release and we can't break backwards compatibility…
>>> 
>>> How's that sound?
>> 
>> 
>> Sounds good. Thanks for taking time to look at this :)
>> 
>>> 
>>> Attila.
>>> 
>>> On Nov 27, 2014, at 2:46 PM, Attila Szegedi <[email protected]> 
>>> wrote:
>>> 
>>>> Also, the documentation for both List and Map interfaces prescribes an 
>>>> exact algorithm[1][2] that every implementation of them must use to 
>>>> calculate their hashCode(), and they too are incompatible. This is not as 
>>>> insurmountable as a javac error, but still not a good idea to violate. 
>>>> FWIW, having a separate ArrayMirror that implements only List<Object> 
>>>> might still be workable.
>>>> 
>>>> Attila.
>>>> 
>>>> ---
>>>> [1] http://docs.oracle.com/javase/8/docs/api/java/util/List.html#hashCode--
>>>> [2] http://docs.oracle.com/javase/8/docs/api/java/util/Map.html#hashCode--
>>>> 
>>>> On Nov 27, 2014, at 2:40 PM, Attila Szegedi <[email protected]> 
>>>> wrote:
>>>> 
>>>>> [...]
>>>>> 
>>>>> Unfortunately, we can't subclass ScriptObjectMirror to give you an 
>>>>> ArrayMirror as no Java class can simultaneously implement both List and 
>>>>> Map interfaces due to incompatibility in return types of "Object 
>>>>> Map.remove(Object)" and "boolean List.remove(Object)" :-( Trust me, I was 
>>>>> quite mad when I first realized this.
>>>>> 
>>>>> [...]
>>>>> 
>>>>> Attila.
>>>>> 
>>>>> On Nov 27, 2014, at 2:11 PM, Tim Fox <[email protected]> wrote:
>>>>> 
>>>>>> As you know..
>>>>>> 
>>>>>> In JS, a JSON Object is represented by a JS object, and in the Java 
>>>>>> world it's often represented by Map<String, Object>.
>>>>>> In JS a JSON array is represented by a JS array, and in the Java world 
>>>>>> it's often represented by a List<Object>.
>>>>>> 
>>>>>> I'd love to be able to pass JSON between JS and Java and vice versa with 
>>>>>> the minimum of performance overhead. This is particularly important in 
>>>>>> Vert.x as we chuck a lot of JSON around.
>>>>>> 
>>>>>> Let's say I have a Java interface which expects some JSON:
>>>>>> 
>>>>>> interface SomeInterface {
>>>>>> 
>>>>>> void expectsJSON(Map<String, Object> json);
>>>>>> }
>>>>>> 
>>>>>> Right now I am converting from JS-->Java as follows.
>>>>>> 
>>>>>> var someJson = { foo: "bar"};
>>>>>> String encoded = JSON.stringify(someJson);
>>>>>> Map<String, Object> map = SomeJavaJSONLibrary.decode(encoded);
>>>>>> myObject.expectsJSON(map);
>>>>>> 
>>>>>> As you can see it's pretty clunky. The other direction is equally as 
>>>>>> clunky. And it's slow as we're encoding/decoding everything via String.
>>>>>> 
>>>>>> Then I realised that if I pass a JS object directly into the expectsJSON 
>>>>>> method Nashorn will provide me with a Map<String, Object> that backs the 
>>>>>> original object. I.e. I can do this:
>>>>>> 
>>>>>> var someJson = { foo: "bar"};
>>>>>> myObject.expectsJSON(map);
>>>>>> 
>>>>>> Yay! No encoding overhead. Fast. :)
>>>>>> 
>>>>>> And it works with nested json:
>>>>>> 
>>>>>> var someJson = { foo: "bar", nested: { wibble: "blah"}};
>>>>>> 
>>>>>> Just when I was getting my hopes up that this would be a great super 
>>>>>> fast way of transferring JSON betwen Java and JS, I tried it with a nest 
>>>>>> array:
>>>>>> 
>>>>>> var someJson = { foo: "bar", nestedArray: [123, 456]};
>>>>>> 
>>>>>> But in Java, map.get("nestedArray") returns a ScriptObjectMirror not a 
>>>>>> List as I was hoping. :(
>>>>>> 
>>>>>> So.. passing from JS to Java: JS Object maps to Map, but JS Array maps 
>>>>>> to ScriptObjectMirror. (Seems a bit asymmetric?).
>>>>>> 
>>>>>> Any reason why we can't map JS Array to Java list when calling JS->Java? 
>>>>>> (Perhaps this is related to my previous question backing a JS Array with 
>>>>>> a List...)
>>>>>> 
>>>>>> Do you have any other suggestions for transferring JSON between JS and 
>>>>>> Java without too much encoding overhead?
>>>>>> 
>>>>>> Thanks again!
> 

Reply via email to