2016-04-25 5 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は、今では以前numberを返しますobjectを返します。

私の質問は意図的な動作かバグですか?私はまずこれがバグだろうが、JDK-8010732がそうでなければ示唆しているようだ。

答えて

7

Nashornの最初のリリースでは、すべての数値Javaプリミティブとjava.lang.NumberのすべてのサブクラスがJavaScript番号として扱われました。ただし、double型として定義されたJavaScriptの数値は、longやjava.lang.BigDecimalsなどの倍精度にマップされない数値型は、JavaScriptの数値に変換すると精度が低下することを意味します。

お気づきのように、私たちはこれを8u77から8u92の間で修正しました。ダブルスにきれいにマッピングできないjava.lang.Numberのインスタンスは、もは​​やNashornのJavaScript番号として扱われません。

これを回避するには、2つの方法があります。 1つは、これらの数値をJavaオブジェクトとして扱い、Javaクラスが提供するメソッドを使用することです。これは通常、Javaクラスが手元の数値型で動作するように書かれているため、より良いオプションです。もう1つのオプションは、明示的にJavaScript番号に変換することです。これは、通常、グローバルなNumber()コンストラクタを "new"キーワードなしで呼び出すことによって、または単項 "+"演算子の前に追加することによって実行されます。ただし、この変換は気づかないうちに精度が失われる可能性があるため、最初のオプションはおそらくより安全なパスです。

+0

JDK 8のリリースノートでこれについての説明はありませんでした。 @ hannes-wallnöferによって参照されるバグは、https://bugs.openjdk.java.net/browse/JDK-8146264です。 –

関連する問題