You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Graal.js返回SafeInteger致断言失败:TestNG与独立Java应用差异及解决

问题:Nashorn迁移Graal.js的数值映射异常——TestNG与独立应用行为差异

背景

我们正将遗留代码从Nashorn迁移至Graal.js,遇到数值内部映射不一致问题:

  • Nashorn将15位大整数映射为java.lang.Double
  • Graal.js则解析为实现TruffleObject的SafeInteger

这导致多语言互操作逻辑中的断言assert !(result instanceof TruffleObject);失效。更反常的是:该断言在TestNG测试中失败,但在独立Java应用中可通过——独立应用返回SafeInteger,测试环境返回null。

简化测试用例

@Test
public static void test() throws ScriptException {
    Scope scope = ScriptManager.createScope();
    
    String test = "314159265358979";

    scope.setValue(new Variable("maxPrecisionJavascript", DataType.NUMBER), test);
    Expression expr1 = ScriptManager.createExpression("result = maxPrecisionJavascript;");
    expr1.eval(scope);
    String actual = scope.getValueAsString("result");
    System.out.println("Result: " + actual);
}

错误栈信息

测试环境执行scope.getValueAsString("result")时触发断言错误:

org.graalvm.polyglot.PolyglotException: java.lang.AssertionError
    at com.oracle.truffle.polyglot.HostToGuestRootNode.execute(HostToGuestRootNode.java:125)
    ...
    at com.tibco.bpm.se.core.test.GraalTest.test(GraalTest.java:56)
Caused by: java.lang.AssertionError
    at com.oracle.truffle.polyglot.HostToGuestRootNode.execute(HostToGuestRootNode.java:125)

核心疑问

  1. 为何SafeInteger(TruffleObject实现类)会导致断言在TestNG测试失败但独立应用通过?
  2. TestNG与运行时环境在Graal.js行为或多语言引擎配置上有已知差异吗?
  3. 如何解决大数值适配问题?

解答

一、TestNG与独立应用的行为差异原因

  1. 断言启用状态不同:TestNG默认可能启用了Java断言(-ea参数),而独立应用未开启。Graal.js内部HostToGuestRootNode的断言在测试环境被触发,独立应用因断言关闭而跳过,这是最常见的诱因。
  2. 引擎配置差异:TestNG测试环境可能使用了不同的Polyglot引擎配置,比如是否开启js.safe-integers属性,或者测试框架的类加载器隔离导致Graal.js内部对象处理逻辑异常,进而出现返回null的情况。
  3. Scope生命周期问题:测试环境中Scope对象可能被Test框架提前回收或重置,导致result变量未正确保留,最终返回null触发断言失败;独立应用中Scope生命周期更可控,值能正常留存。

二、TestNG与Graal.js的已知配置差异

TestNG的测试上下文通常使用自定义类加载器,可能影响Graal.js的Polyglot引擎初始化:

  • Graal.js依赖Truffle框架的类加载机制,TestNG的类加载隔离可能导致instanceof TruffleObject的类型判断出现偏差。
  • 部分TestNG插件或配置会修改JVM参数,意外开启/关闭Graal.js的特性(如安全整数模式)。

三、大数值适配的解决方案

1. 调整Graal.js数值映射行为

通过Polyglot引擎配置强制将大整数转为Java原生类型,避免生成SafeInteger:

Engine engine = Engine.newBuilder()
    .option("js.safe-integers", "false") // 关闭安全整数模式,大整数转为Double
    .build();

若需保留整数精度,可在脚本中主动将数值转为BigInt后再交互,或使用Number.prototype.toString()显式转换。

2. 修改断言逻辑适配Graal.js

放弃对TruffleObject的强断言,改为判断数值类型:

// 替换原断言
assert result instanceof Number || result instanceof BigInteger;
// 或使用Graal.js工具类判断
assert Value.asValue(result).isNumber();

3. 统一测试与生产环境的JVM参数

确保TestNG测试和独立应用使用相同的JVM参数,尤其是断言开关(-ea/-da)和Graal.js相关配置,消除环境差异导致的行为不一致。

4. 修复Scope变量生命周期问题

检查测试代码中Scope的创建与销毁逻辑,确保expr1.eval(scope)后result变量未被意外清空。可在测试中显式打印scope内的所有变量,验证值是否正确存在。


内容的提问来源于stack exchange,提问作者Srikanth Allapu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:57:26