java - GraalSDK 值作为 JSON 结构
问题描述
我试图让 JavaScript 调用的结果类似于 Map<String,Object> 的 JSON 结构,其中值可能是数字、字符串、布尔值、对象(地图)或数组(列表),类似于杰克逊所做的如果将值转换为地图。
使用Value.as(Map.class)
调用时,我希望 Map 中的值遵循这些规则
如果使用原始 Map.class 或 Object 组件类型,则列表的返回类型递归地服从 Object 目标类型映射规则。
进一步了解文档(对象映射规则 8)
如果该值具有数组元素并且其数组大小小于或等于 Integer.MAX_VALUE,则结果值将实现 List。
然而这个测试失败了
public class TestGraalMap {
static String JS_CODE = "(function myFun(){ return { listProperty: ['listValue']};})";
@Test
public void testList() {
try (Context context = Context.create()) {
Value value = context.eval("js", JS_CODE);
Value result = value.execute();
Map<String,Object> resultMap = result.as(Map.class);
assertThat(resultMap).hasEntrySatisfying("listProperty", testArray -> {
assertThat(testArray).asList().containsExactly("listValue");
});
}
}
}
出现以下错误。
Expecting:
<{}>
to be an instance of:
<java.util.List>
but was instance of:
<com.oracle.truffle.polyglot.PolyglotMap>
我错过了什么?
解决方案
是的,有关于默认对象目标强制的规则 8 [1]。然而,这些规则是按顺序执行的。因此,在此之前,规则 7 规定如果 Value 有成员,那么它将被转换为 Map。此规则适用于 JavaScript 对象,因为它们同时具有成员和数组元素。可以说这种行为是违反直觉的,但 GraalVM 从 Nashorn 等其他引擎继承了这一点。GraalVM 团队仍在讨论默认情况下是否可以更改此行为,但那是 tbd。
同时,polyglot API 有一个称为目标类型映射的简洁功能,您可以使用它以您需要的方式自定义这些映射。这是您的情况所需要的:
static String JS_CODE = "(function myFun(){ return { listProperty: ['listValue']};})";
@Test
public static void test {
HostAccess access = HostAccess.newBuilder(HostAccess.EXPLICIT)
.targetTypeMapping(
// for any conversion Any Value -> Object
Value.class, Object.class,
// if the value has array elements and members
(v) -> v.hasArrayElements() && v.hasMembers(),
// convert to List (instead of Map)
(v) -> v.as(List.class)).build();
try (Context context = Context.newBuilder().allowHostAccess(access).build()) {
Value value = context.eval("js", JS_CODE);
Value result = value.execute();
Map<String, Object> resultMap = result.as(Map.class);
assertThat(resultMap).hasEntrySatisfying("listProperty", testArray -> {
assertThat(testArray).asList().containsExactly("listValue");
});
}
}
[1] https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#as-java.lang.Class-
推荐阅读
- ansible - Ansible:在 postgres 中将角色附加到用户
- java - 我的 jScrollPane 在我的 AbstractTableModel 上不起作用
- python - 在没有 GoogleService-Info.plist 的情况下将调试符号上传到 Crashlytics
- eclipse-che - 无法在 kubernetes 上运行 eclipse che
- amazon-web-services - 如何为多个账户使用 AWS CLI
- typescript - 打字稿条件属性未能用于函数参数
- dask-distributed - 您可以使用从数据已分区的现有 MPI 作业分发的 Dask 吗?
- c++ - std::optional:简单和引用限定值()之间的有效区别
- amazon-web-services - AWS Chalice - 发送文件作为响应
- asp.net-core - Azure Devops 中应用程序和配置设置的语法