如何将 Map 从 Java 传递到 graal.js?
How can I pass a Map from Java to graal.js?
我在 Scala/Java 中有一个地图,我希望在 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 {}'。 None 个在地图中有任何值。
如何让在 JVM 上创建的地图数据在 graal.js Javascript 代码中可见(最好是 Javascript 本身)?
好的,这实际上似乎是 Scala 与 Java 的对比。在 Scala 中,如果 Map 的内容被转换为 graal Value,我可以成功传递它。没有问题。我可以成功地传递一个 Scala 对象(case 或 non-case)并调用该对象的方法,但是......我 不能 访问对象的数据成员,即使他们'物超所值!
如果我创建一个纯 Java class,我可以在 graal 中访问 class 的数据成员和方法。
不确定为什么会这样...non-case Scala class 基本上应该与 Java class 相同,但显然存在一些重要的区别到格拉尔。
幸运的是,我想我现在可以忍受这种差异。
您可以使用 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
}
使用 ProxyObject.fromMap
帮助我们将映射从 Java 传递到 graal javascript。请参阅 here 了解更多详情。
一个快速的工作示例。
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();
}
}
}
我在 Scala/Java 中有一个地图,我希望在 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 {}'。 None 个在地图中有任何值。
如何让在 JVM 上创建的地图数据在 graal.js Javascript 代码中可见(最好是 Javascript 本身)?
好的,这实际上似乎是 Scala 与 Java 的对比。在 Scala 中,如果 Map 的内容被转换为 graal Value,我可以成功传递它。没有问题。我可以成功地传递一个 Scala 对象(case 或 non-case)并调用该对象的方法,但是......我 不能 访问对象的数据成员,即使他们'物超所值!
如果我创建一个纯 Java class,我可以在 graal 中访问 class 的数据成员和方法。
不确定为什么会这样...non-case Scala class 基本上应该与 Java class 相同,但显然存在一些重要的区别到格拉尔。
幸运的是,我想我现在可以忍受这种差异。
您可以使用 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
}
使用 ProxyObject.fromMap
帮助我们将映射从 Java 传递到 graal javascript。请参阅 here 了解更多详情。
一个快速的工作示例。
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();
}
}
}