问题描述
使用GraalVM将Java对象公开给JavaScript,我使用ProxyObject
来包装它们。为此,我正在使用ProxyObject.fromMap
方法,如下所示:
ProxyObject exposedobject = ProxyObject.fromMap(objectMapper.convertValue(javaObject,Map.class));
在这里,javaObject
是Object
类的,可以任意复杂。此方法适用于javaObject
的直接成员,但不适用于成员本身是复杂对象的情况。例如,如果javaObject
的成员之一恰好是Map
,例如:
final Map<String,Object> source = new HashMap<>();
source.put("id","1234567890");
final Map<String,Object> sourceComponent = ImmutableMap.of("key","value");
source.put("complex",sourceComponent);
// assuming the source is any object
ProxyObject exposedobject = ProxyObject.fromMap(objectMapper.convertValue(source,Map.class));
// or kNowing that source is in fact a map
ProxyObject exposedobject = ProxyObject.fromMap(source);
在JavaScript中访问exposedobject
时会发生以下情况:
exposedobject; // returns {complex: JavaObject[com.google.common.collect.SingletonImmutableBiMap],id: "1234567890"}
exposedobject.id; // returns 01234567890
exposedobject.complex; // returns {key=value}
exposedobject.complex.key; // returns undefined
所以我的问题是,我们如何才能将任意复杂而深入的java对象暴露给javascript。我们是否必须递归遍历所有成员并将它们包装到ProxyObject
中?还是有一种现成的受支持的现成方法?
另外,请告诉我我的方法是否需要更改。
解决方法
就像ProxyObject [1]的javadoc所说的“要实现的接口以模仿包含成员的来宾语言对象。”这意味着,如果您希望Java对象像JavaScript本身一样在JavaScript中使用,则它必须是ProxyObject。
另一方面,如网站文档[2]所示,传递给JavaScript的Java对象仍可以用作Java对象(即默认情况下它们不模仿JS对象)。这意味着您可以访问字段,调用方法等。 网站文档显示了一个示例:
public static class MyClass {
public int id = 42;
public String text = "42";
public int[] arr = new int[]{1,42,3};
public Callable<Integer> ret42 = () -> 42;
}
public static void main(String[] args) {
try (Context context = Context.newBuilder()
.allowAllAccess(true)
.build()) {
context.getBindings("js").putMember("javaObj",new MyClass());
boolean valid = context.eval("js"," javaObj.id == 42" +
" && javaObj.text == '42'" +
" && javaObj.arr[1] == 42" +
" && javaObj.ret42() == 42")
.asBoolean();
assert valid == true;
}
}
[1] https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/proxy/ProxyObject.html
[2] https://www.graalvm.org/reference-manual/embed-languages/