2016-04-25 15 views
6

Abbiamo eseguito l'aggiornamento da Oracle JDK 8u77 a 8u92 e improvvisamente gli script che in precedenza funzionavano non funzionano più. Un riproduttore minima è:Nashorn non funziona più con 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)); 

In precedenza abbiamo ottenuto

0.00 

Ma ora stiamo ottenendo.

TypeError: GROSSREIMBAMOUNT.toFixed is not a function 

typeof ora ritorna object dove sarebbe in precedenza tornare number.

La mia domanda è questo comportamento intenzionale o un bug? Per prima cosa però sarebbe un errore ma il JDK-8010732 sembra suggerire il contrario.

risposta

7

La versione iniziale di Nashorn ha trattato tutti i primitivi Java numerici e tutte le sottoclassi di java.lang.Number come numeri JavaScript. Tuttavia, i numeri JavaScript sono definiti come doppi, e ciò significa che i tipi numerici che non corrispondono a doppi come long o java.lang.BigDecimals risentiranno della perdita di precisione quando convertiti in un numero JavaScript.

Come notato, abbiamo risolto questo problema tra 8u77 e 8u92. Le istanze di java.lang.Number che non possono essere mappate in modo pulito in duplicati non vengono più trattate come numeri JavaScript in Nashorn.

Hai due opzioni per ovviare a questo problema. Uno consiste nel trattare questi numeri come oggetti Java e utilizzare i metodi forniti dalla classe Java. Questa è solitamente l'opzione migliore in quanto la classe Java è stata scritta per funzionare con il tipo numerico a portata di mano. L'altra opzione è convertire esplicitamente in un numero JavaScript. Questo di solito viene fatto chiamando il costruttore globale Number() senza la parola chiave "new" o semplicemente anteponendo l'operatore unario "+". Si noti tuttavia che questa conversione può comportare una perdita di precisione senza che si noti, quindi la prima opzione è probabilmente il percorso più sicuro.

+0

Non ho trovato alcuna menzione di questo in JDK 8 note di rilascio. Il bug a cui fa riferimento @ hannes-wallnöfer è https://bugs.openjdk.java.net/browse/JDK-8146264 –