2016-04-25 84 views
6

我们从Oracle JDK 8u77升级到8u92,突然之前正在工作的脚本不再有效。一个最小的再现是:Nashorn不再使用BigDecimal

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)); 

此前我们得到了

0.00 

但现在我们正在。

TypeError: GROSSREIMBAMOUNT.toFixed is not a function 

typeof现在返回object而这在以前将返回number

我的问题是这种行为故意或错误?我首先虽然这将是一个错误,但JDK-8010732似乎表明否则。

回答

7

Nashorn的初始版本将所有数字Java原语和java.lang.Number的所有子类都视为JavaScript数字。然而,JavaScript数字定义为双精度,这意味着数字类型不会映射为双精度(如longs或java.lang.BigDecimals),但转换为JavaScript数字时将会失去精度。

正如您所注意到的,我们在8u77和8u92之间修正了这个问题。不能将干净地映射到双精度的java.lang.Number实例不再视为Nashorn中的JavaScript数字。

有两种方法可以解决这个问题。一种是将这些数字视为Java对象,并使用Java类提供的方法。这通常是更好的选择,因为Java类被编写用于处理数字类型。另一种选择是显式转换为JavaScript数字。这通常是通过调用没有“new”关键字的全局Number()构造函数,或者通过预先加入一元“+”运算符来完成的。但请注意,如果不注意,此转换可能会导致精度损失,因此第一个选项可能是更安全的路径。

+0

我在JDK 8发行说明中没有发现任何提及。 @ hannes-wallnöfer引用的错误是https://bugs.openjdk.java.net/browse/JDK-8146264 –