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