我们从Oracle JDK 8u77升级到8u92,突然之前运行的脚本不再有效.最小的复制者是:
Map<String, Object> attributes = Collections.singletonMap("GROSSREIMBAMOUNT", BigDecimal.ZERO);
String script = "GROSSREIMBAMOUNT.toFixed(2)";
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
for (Entry<String, Object> entry : attributes.entrySet()) {
jsEngine.put(entry.getKey(), entry.getValue());
}
System.out.println(jsEngine.eval(script));
Run Code Online (Sandbox Code Playgroud)
以前我们得到了
0.00
Run Code Online (Sandbox Code Playgroud)
但现在我们得到了.
TypeError: GROSSREIMBAMOUNT.toFixed is not a function
Run Code Online (Sandbox Code Playgroud)
typeof现在返回object之前返回的位置number.
我的问题是这种行为故意还是一个错误?我首先虽然这将是一个错误,但JDK-8010732似乎暗示不然.
Nashorn的初始版本将所有数字Java原语和java.lang.Number的所有子类视为JavaScript编号.但是,JavaScript数字定义为双精度数,这意味着未映射到双精度数字类型(如long或java.lang.BigDecimals)将在转换为JavaScript数时失去精度.
正如您所注意到的,我们在8u77和8u92之间修复了这个问题.无法将干净地映射到双精度的java.lang.Number实例不再被视为Nashorn中的JavaScript编号.
您有两种方法可以解决此问题.一种是将这些数字视为Java对象,并使用Java类提供的方法.这通常是更好的选择,因为编写Java类是为了使用手头的数字类型.另一种选择是显式转换为JavaScript编号.这通常是通过调用没有"new"关键字的全局Number()构造函数,或者只是在前面加上一元"+"运算符来完成的.但请注意,如果没有您注意到,此转换可能会导致精度损失,因此第一个选项可能是更安全的路径.
| 归档时间: |
|
| 查看次数: |
719 次 |
| 最近记录: |