Graaljs: [interop] Java List is not mapped to JS Array

Created on 27 Dec 2018  路  8Comments  路  Source: oracle/graaljs

Hello.
I've an issue with interop from Java to Graal.js
In my case i have a function like that:

public Object getValue(String key) {
    return storage.get(key);
}

Where storage may have any values, like List.

When I call from JS thi method like this:

const value = module.getValue("test"); // that will return ArrayList

I've got an error: (java.util.ArrayList)] failed due to: Unknown identifier: map when I call value.map()

How to deal with it?

enhancement

All 8 comments

An instance of java.util.ArrayList behaves like JS Array in various aspects (for example, elements can be accessed using list[index] syntax). Unfortunately, instances of java.util.ArrayList do not have its prototype set to Array.prototype (there are some good reasons for that). That's the reason why map function is not found on your value. You can workaround that by calling Array.prototype.map.call(value, mapping) instead of value.map(mapping). If you cannot do that (for example, if this code is part of some 3rd party library) then you can convert java.util.ArrayList to JS Array manually using Java.from(value) (this will create JS Array that is a shallow copy of the given list).

@iamstolis java.util.ArrayList implements standard java.util.List, why do not map any java.util.List to Array
For example, nashorn do that.
Also when interop from JS to Java grall.js map Array to List of java method that have List in signature

public void setValue(String key, List value)
...

Also, JS code develop another team, that uses our API, I cannot to force them to use Array.prototype.map.call(value, mapping) it's very ridiculous

I understand that the current situation is not optimal. Putting Array.prototype on the prototype chain of Array-like non-JavaScript objects comes with some technical difficulties and may lead to some confusing behaviour as well (Object.getPrototypeOf(object) being different from object.__proto__, for example) but we will consider it definitely as you are not the first one who run into this kind of issue.

java.util.ArrayList implements standard java.util.List, why do not map any java.util.List to Array For example, nashorn do that.

AFAIK, Nashorn has the same issue:

$ jdk8\bin\jjs
jjs> var list = new java.util.ArrayList();
jjs> list.map(function(x) { return x; })
<shell>:1 TypeError: [] has no such function "map"

Sorry for nashorn, I'm mixed up with interop from JS to Java.
Ok, Sounds like a reason.
I see only workaround that and create JS array in java, or converty to string and parse as JSON from context bindings

@iamstolis Any plans or ETA for supporting automatic mapping from java.util.List to Array?

I have just merged an experimental support for Array.prototype on the prototype chain of array-like non-JavaScript objects (see https://github.com/graalvm/graaljs/commit/4b76fdd578d0b089ec4c3fd357531df0228cd8db), i.e., I have modified various parts of graal-js to behave as if Array.prototype was the prototype of array-like non-JS objects. You have to set js.experimental-array-prototype flag to enable this feature.

There are some rough edges and corner cases that will not work but the test-case mentioned in this issue works definitely:

$ mx js --js.experimental-array-prototype
> var list = new java.util.ArrayList(); list.add(3); list.add(5); list.map(function(x) { return x*x; });
(2) [9, 25]

Please, give it a try and let us know if it works for you. Unfortunately, this change didn't make it into soon-to-be-released GraalVM 1.0.0-rc11. So, you either have to build graal-js/GraalVM on your own or wait for GraalVM 1.0.0-rc12.

FYI: js.experimental-array-prototype option that adds Array.prototype on the prototype chain of array-like non-JavaScript objects will be removed in GraalVM 1.0.0-rc14. It will replaced by js.experimental-foreign-object-prototype option. We changed the name of this option because besides adding Array.prototype it also adds Function.prototype on the prototype chain of executable non-JavaScript objects and Object.prototype on the prototype chain of all non-JavaScript objects now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pmlopes picture pmlopes  路  3Comments

theonlygusti picture theonlygusti  路  5Comments

provegard picture provegard  路  4Comments

frieck picture frieck  路  6Comments

lucifer1004 picture lucifer1004  路  3Comments