Fast passing of JSON between JS and Java (and vice versa)
Tony Zakula
tonyzakula at gmail.com
Tue Jun 30 11:51:50 UTC 2015
That is great. We will leverage this right away. Thanks.
Tony
On Mon, Jun 29, 2015 at 2:12 PM, Attila Szegedi <attila.szegedi at oracle.com>
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 <attila.szegedi at oracle.com>
> 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 <timvolpe at gmail.com> 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 <attila.szegedi at oracle.com>
> 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 <
> attila.szegedi at oracle.com> 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 <timvolpe at gmail.com> 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!
> >
>
>
More information about the nashorn-dev
mailing list