[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-nashorn-dev
Subject:    Re: Fast passing of JSON between JS and Java (and vice versa)
From:       Tim Fox <timvolpe () gmail ! com>
Date:       2014-11-27 19:08:25
Message-ID: 547776A9.1070805 () gmail ! com
[Download RAW message or body]

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@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@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@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!
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic