Нашхорн больше не работает с BigDecimal

Мы обновили 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));

Ранее мы получили

0.00

Но теперь мы получаем.

TypeError: GROSSREIMBAMOUNT.toFixed is not a function

typeof теперь возвращает object вместо того, чтобы раньше возвращать number.

Мой вопрос, это поведение преднамеренное или ошибка? Сначала я подумал, что это ошибка, но JDK-8010732, кажется, предполагает обратное.


person Philippe Marschall    schedule 25.04.2016    source источник


Ответы (1)


Первоначальный выпуск Nashorn рассматривал все числовые примитивы Java и все подклассы java.lang.Number как числа JavaScript. Однако числа JavaScript, определенные как двойные, и это означает, что числовые типы, которые не отображаются на двойные числа, такие как longs или java.lang.BigDecimals, будут страдать от потери точности при преобразовании в число JavaScript.

Как вы заметили, мы исправили это между 8u77 и 8u92. Экземпляры java.lang.Number, которые не могут быть четко сопоставлены с числами типа double, больше не рассматриваются как числа JavaScript в Nashorn.

У вас есть два варианта обойти это. Один из них — рассматривать эти числа как объекты Java и использовать методы, предоставляемые классом Java. Обычно это лучший вариант, поскольку класс Java был написан для работы с имеющимся числовым типом. Другой вариант — явно преобразовать в число JavaScript. Обычно это делается путем вызова глобального конструктора Number() без ключевого слова "new" или путем простого добавления унарного оператора "+". Обратите внимание, однако, что это преобразование может привести к потере точности без вашего ведома, поэтому первый вариант, вероятно, является более безопасным путем.

person Hannes Wallnöfer    schedule 25.04.2016
comment
Я не нашел упоминания об этом в примечаниях к выпуску JDK 8. Ошибка, на которую ссылается @hannes-wallnöfer, — это bugs.openjdk.java.net/browse/JDK. -8146264 - person Vineet Bhatia; 17.12.2017
comment
Как вы сказали, нужно просто рассматривать эти числа как объекты Java и использовать методы, предоставляемые классом Java. Мне очень хотелось узнать, как вы поддерживаете запуск методов Java в коде javascript... звучит волшебно - person Tommy.Tang; 15.07.2019