Java中的Graal嵌入式JavaScript,如何从Java调用列表/数组上的map?有可能吗?

时间:2019-04-03 15:55:18

标签: java graalvm

我正在与Graal一起玩,以将javascript作为来宾语言运行,并且想知道是否可以在主机(Java)对象或代理上使用javascript Array.map功能。演示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")

}

使用ProxyArray在我看来是最有前途的,但是我仍然无法使用它。预计将支持此功能吗?

编辑:使用可接受的答案,代码可以正常工作,这是针对感兴趣者的更改:

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

1 个答案:

答案 0 :(得分:4)

问题的根源在于,默认情况下,类似数组的非JavaScript对象的原型链上没有Array.prototype。因此,无法使用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就可以使用了。