Java与GraalJS ScriptEngine变量交互问题及解决方法咨询
问题解答
1. 数组、List、Map绑定后无内容的原因
GraalJS默认把Java集合(数组、List、Map这类)以原生Java对象实例的形式暴露给JS环境,不会自动转换成JavaScript原生的Array或Object类型。JS的JSON.stringify和遍历逻辑只认对象的可枚举属性,但Java集合的元素、键值对不是以JS可枚举属性的形式存在,得通过Java的方法(比如get()、size())才能访问,所以直接用JS的方式操作就会得到空对象{}。
2. 解决方法
方法一:用GraalJS的Value类手动转换
借助GraalVM提供的org.graalvm.polyglot.Value类,把Java集合主动转成JS原生类型:
import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; import java.util.Arrays; import java.util.List; import java.util.Map; // 初始化JS上下文 Context context = Context.create("js"); // 转换Java List为JS数组 List<String> javaList = Arrays.asList("a", "b", "c"); Value jsArray = context.asValue(javaList); context.getBindings("js").putMember("jsList", jsArray); // 转换Java Map为JS对象 Map<String, Integer> javaMap = Map.of("key1", 1, "key2", 2); Value jsObj = context.asValue(javaMap); context.getBindings("js").putMember("jsMap", jsObj); // 转换Java数组为JS原生数组 int[] javaArray = new int[]{1,2,3}; Value jsNativeArray = context.asValue(javaArray); context.getBindings("js").putMember("jsArray", jsNativeArray);
这样在JS里就能正常用JSON.stringify(jsList)或者遍历操作了。
方法二:配置Context开启自动类型转换
创建Context时设置js.java-handler-properties参数,让Java集合自动映射成JS原生类型:
import org.graalvm.polyglot.Context; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; Context context = Context.newBuilder("js") .option("js.java-handler-properties", "true") .build(); // 直接绑定Java集合即可 List<String> javaList = Arrays.asList("x", "y", "z"); context.getBindings("js").putMember("myList", javaList); Map<String, String> javaMap = new HashMap<>(); javaMap.put("name", "test"); context.getBindings("js").putMember("myMap", javaMap);
这个配置会让GraalJS自动把Java的List转成JS数组、Map转成JS对象,Java数组也会转成JS原生数组。
方法三:手动JSON序列化(通用兼容方案)
如果不想依赖GraalVM的特定API,可以用Jackson这类JSON库先把Java集合序列化成JSON字符串,再在JS里解析:
import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Arrays; import java.util.List; import java.util.Map; ObjectMapper mapper = new ObjectMapper(); List<String> javaList = Arrays.asList("foo", "bar"); String listJson = mapper.writeValueAsString(javaList); context.getBindings("js").putMember("listJson", listJson); Map<String, Integer> javaMap = Map.of("age", 20, "score", 90); String mapJson = mapper.writeValueAsString(javaMap); context.getBindings("js").putMember("mapJson", mapJson);
在JS中执行解析:
const myList = JSON.parse(listJson); const myMap = JSON.parse(mapJson);
内容的提问来源于stack exchange,提问作者谢良基
相关产品推荐
相关产品推荐

