Graal在java中嵌入了javascript,如何从java调用列表/数组上的映射?是否可以?

Dan*_*y G 1 java graalvm

我正在使用 Graal 将 javascript 作为来宾语言运行,并且想知道是否有一种方法可以Array.map在主机(Java)对象或代理上使用 javascript 功能。下面是演示 Kotlin 代码,但应该与 Java 代码足够接近。

fun main() {
    val context = Context.newBuilder().build()
    val javaOutputList = mutableListOf<Integer>()
    val javaList = listOf(2, 2, 3, 4, 5)
    val proxyJavaList = ProxyArray.fromList(javaList)

    context.polyglotBindings.apply {
        putMember("javaOutputList", javaOutputList)
        putMember("javaList", javaList)
        putMember("proxyJavaList", proxyJavaList)
    }

    val script = """
        var javaOutputList = Polyglot.import('javaOutputList');
        var javaList = Polyglot.import('javaList');
        var proxyJavaList = Polyglot.import('proxyJavaList');

        var abc = [1, 2, 3];
        abc.forEach(x => javaOutputList.add(x));      // WORKS

        //abc.map(x => x + 1)             // WORKS
        //javaList.map(x => x + 1)        // DOES NOT WORK (map not a method on list)
        proxyJavaList.map(x => x + 1)     // DOES NOT WORK (message not supported: INVOKE)
    """.trimIndent()

    val result = context.eval("js", script)

    val resultList = result.`as`(List::class.java)
    println("result: $resultList")
    println("javaOutputList: $javaOutputList")

}
Run Code Online (Sandbox Code Playgroud)

使用对ProxyArray我来说看起来是最有希望的,但我仍然无法让它发挥作用。预计会支持此功能吗?

编辑:通过接受的答案,代码可以工作,以下是感兴趣的更改:

    val context = Context.newBuilder()
            //.allowExperimentalOptions(true)  // doesn't seem to be needed
            .option("js.experimental-foreign-object-prototype", "true")
            .build()
Run Code Online (Sandbox Code Playgroud)

Jan*_*ola 6

Array.prototype问题的根源在于,类数组的非 JavaScript 对象默认情况下没有原型链。因此,Array.prototype.map无法使用javaList.map/proxyJavaList.map语法访问。

您可以Array.prototype.map直接调用Array.prototype.map.call(javaList, x => x+1),也可以使用实验性选项js.experimental-foreign-object-prototype=true(我们最近添加的),该选项添加Array.prototype到所有类数组对象的原型链上。javaList.map/proxyJavaList.map届时即可使用。