0

我在 Scala/Java 中有一个 Map 我希望在 graal.js 引擎上运行的 Javascript 中可见。

case class Thing() {
  def foo() { println("FOO!") }  // just to see if this is callable from js (it is)
  val m = Map("foo" -> "bar", "one" -> 1)
  val d1 = m
  val d2 = m.asJava
  val d3 = toGraalValue(m)
  val d4 = MapProxyObject(m.map { case (k, v) => (k.toString, toGraalValue(v)) })

  def toGraalValue(a: Any): Value =
    a match {
      case s: List[_]   => Value.asValue(ListProxyArray(s.map(toGraalValue).toArray))
      case m: Map[_, _] => Value.asValue(MapProxyObject(m.map { case (k, v) => (k.toString, toGraalValue(v)) }))
      case _            => Value.asValue(a)
    }
}

后来,graal.js 中的一个 Javascript 函数被调用:

inv.invokeFunction(bindFn, args: _*) 

其中 bindFn 是一个编译函数(如下),而 args 是一个包含我的 Thing 对象的 1 元素列表。

Javascript:

function(thing) {
  console.log(thing.d1);
  console.log(thing.d2);
  console.log(thing.d3);
  console.log(thing.d4);
  console.log(thing.foo());
}

thing.foo() 的输出有效,但所有其他输出在 Javascript 中解析为“foreign {}”。它们在地图中都没有任何值。

如何获取在 graal.js Javascript 代码(最好是原生到 Javascript)中可见的 JVM 上创建的 Map 数据?

4

3 回答 3

1

您可以使用sj4js库。它支持 Java HashMaps 和 Arrays 等类型。

// create a JS hash map
JsHashMap hm = new JsHashMap();
hm.putMember("a", "A");
hm.putMember("b", "B");
hm.putMember("c", "C");

try (JScriptEngine engine = new JScriptEngine()) {

    // add the hm to js
    engine.addObject("test", hm);
    
    // evaluate Js code
    engine.exec("test['b']");
    // B
    
    engine.exec("test.b");
    // B
    
    engine.exec("for (a in test) { console.log(test[a]); }");
    // a, b, c
    
} 
于 2021-03-09T19:38:51.893 回答
1

使用ProxyObject.fromMap帮助我们将地图从 Java 传递到 graal javascript。有关详细信息,请参阅此处

一个快速工作的例子。

import java.util.HashMap;
import java.util.Map;

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.proxy.ProxyObject;

public class TransformJson {

    public TransformJson() {
        // TODO Auto-generated constructor stub
    }

    static String SOURCE = "function transformJson(prmPayload) {"
            + " console.log('payload = ' + JSON.stringify(prmPayload));" + " console.log('from javascript'); "
            + " return {" + " 'emp' : {" + "   'id' : prmPayload.emp_id" + "   ,'name' : {"
            + "      first : prmPayload.emp_first_name" + "      ,last: prmPayload.emp_last_name" + "}" + "} " + "};}";

    public static void main(String[] args) {
        try (Context context = Context.create()) {
            context.eval(Source.newBuilder("js", SOURCE, "src.js").build());
            Value transformJson = context.getBindings("js").getMember("transformJson");
            Map payload = new HashMap();
            payload.put("emp_id", 1);
            payload.put("emp_first_name", "John");
            payload.put("emp_last_name", "Chambers");
            payload.put("emp_dept_id", 25);
            payload.put("emp_dept_name", "Technology");
            Value returnVal = transformJson.execute(ProxyObject.fromMap(payload));
            System.out.println(returnVal);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
于 2021-04-19T06:23:37.243 回答
0

好的,这实际上似乎是 Scala vs Java 的事情。在 Scala 中,如果 Map 的内容转换为 graal 值,我可以成功传递它。没有问题。我可以成功传递一个 Scala 对象(大小写或非大小写)并调用该对象的方法,但是......我无法访问对象的数据成员,即使它们都是值!

如果我创建一个纯 Java 类,我可以在 graal 中访问该类的数据成员和方法。

不知道为什么会这样……一个非大小写的 Scala 类应该与 Java 类基本相同,但显然存在一些对 graal 很重要的区别。

幸运的是,我认为我现在可以忍受这种差异。

于 2019-05-22T14:55:55.720 回答