Passing Java lists into JS

A. Sundararajan sundararajan.athijegannathan at oracle.com
Thu Nov 27 11:48:52 UTC 2014


* On backed storage being non-array.  
jdk.nashorn.internal.runtime.arrays.ArrayData is "backing store" impl 
for array storage - apart from Java array based impls there is on based 
on nio ByteBuffer. Not sure how feasible is to have one based on List. 
Also, even with one based on List, it would involve wrapping (ArrayData, 
NativeArray instance). But, right now dynalink's magic + nashorn runtime 
magic provides most of what JS Array offers on Java Lists - without 
wrapping as JS arrays.

* And btw, Array.prototype.forEach etc. do work on Java lists

var a = new java.util.ArrayList();
a.add("hello");
a.add("world");
Array.prototype.forEach.call(a, print);
print(Array.prototype.map.call(a, function(e) e.toUpperCase()));

-Sundar

Tim Fox wrote:
> On 27/11/14 10:33, Attila Szegedi wrote:
>> Nashorn explicitly allows [] operator on java lists and it also 
>> supports for…in on them. ".length" is also supported since 8u20, see 
>> <https://bugs.openjdk.java.net/browse/JDK-8039387>.
>>
>> We indeed don't implicitly convert Lists into JS Array objects in 
>> Nashorn. The reason is that JS Array has a Java array as backing 
>> storage; wrapping a large list would incur a lot of copying.
>
> To avoid the copying, could the Nashorn JS Array implementation be 
> changed so it backs either:
>
> a) A Java Array (as it does currently) - this would the case if you 
> created the JS array directly in JS code.
> b) A Java List - this would be the case if a List was passed from Java 
> to JS, providing the user with a JS array
>
> Then we can have our cake and eat it? I.e. we have a real JS Array 
> object (not a half way house with some of the functions and properties 
> but not all), and no copying overhead.
>
>>   You can use "Java.from(someObject.provideList())" to explicitly 
>> convert a Java List to a JS array. We think it's better to provide an 
>> explicit conversion API than incur a linear conversion cost whenever 
>> a List object passes into the JS context.
>> The Java.from created copy is shallow; if you have a List of Lists, 
>> the nested List objects are not converted.
>>
>> Typically you'll want to create a real Array if you want to use Array 
>> functionality that points beyond [], .length, and for…in, e.g. JS 
>> Array comprehension operations (arguably, we *could* implement even 
>> those so that Array.prototype.forEach.call(javaList, ...) works as 
>> expected, but we aren't there yet.)
>>
>> Attila.
>>
>> On Nov 27, 2014, at 10:41 AM, Tim Fox <timvolpe at gmail.com> wrote:
>>
>>> Hello again,
>>>
>>> I am a bit confused about how Lists passed from Java into JS are 
>>> converted.
>>>
>>> I have a Java class as follows:
>>>
>>> public class SomeClass {
>>>
>>>    public List<String> provideList() {
>>>      List<String> list = new ArrayList<>();
>>>      list.add("foo");
>>>      list.add("bar");
>>>      return list;
>>>    }
>>> }
>>>
>>> I call this from JavaScript:
>>>
>>> var io = Packages.io;
>>> var someObject = new io.vertx.scratchpad.SomeClass();
>>>
>>> var arr = someObject.provideList();
>>>
>>> console.log(arr[0]); // prints: foo
>>> console.log(typeof arr.length); // undefined
>>> console.log(arr instanceof Array); // false
>>>
>>> I was under the impression that Nashorn automatically converted Java 
>>> lists passed into JS into JS Arrays.
>>>
>>> The object arr returned in some ways resembles a JavaScript array - 
>>> the operators [] and []= work on it, however it doesn't have the 
>>> array property "length" and it's not an instanceof Array.
>>>
>>> Can anyone clarify to me what this object is? Any reason why Nashorn 
>>> doesn't just wrap it as a real JS Array?
>>>
>>> Cheers
>



More information about the nashorn-dev mailing list