That is great. We will leverage this right away. Thanks. Tony
On Mon, Jun 29, 2015 at 2:12 PM, Attila Szegedi <[email protected]> wrote: > 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! > > > >
