Тестирование, если значение BigDecimal равно нулю в выражении EL JSP

Следующее не всегда ведет себя так, как вы ожидали:

<c:if test="${someBigDecimal == 0}">

Если someBigDecimal имеет значение 0, но имеет шкалу, отличную от 0, операция == возвращает false. То есть, он возвращает true, когда someBigDecimal является новым BigDecimal ( "0" ), но false, когда someBigDecimal является новым BigDecimal ( "0.00" ).

Это результат спецификаций JSP 2.0, 2.1 и 2.2, в которых указано:

Для <, > , < =, > =:

Если A или B - BigDecimal, принуждение A и B к BigDecimal и используйте возвращаемое значение A.compareTo(B).

Для ==,! =:

Если A или B - BigDecimal, принудите и A и B к BigDecimal, а затем:

  • Если оператор равен ==, верните A.equals(B)
  • Если оператор равен! =, return! A.equals(B)

Это означает, что операторы == и != приводят к вызову метода .equals(), который сравнивает не только значения, но также масштаб BigDecimals. Другие операторы сравнения приводят к вызову метода .compareTo(), который сравнивает только значения.

Конечно, будет работать следующее:

<c:if test="${not ((someBigDecimal < 0) or (someBigDecimal > 0))}">

Но это довольно уродливо, есть ли лучший способ сделать это?

Ответы

Ответ 1

В JSP 2.2 EL и выше это выражение будет оцениваться до true:

${someBigDecimal.unscaledValue() == 0}

Это позволит избежать потери точности, но предполагает, что someBigDecimal всегда имеет тип BigDecimal.

A пользовательская функция EL, вероятно, лучший подход для более старых версий EL:

${fn:isZero(someBigDecimal)}

Ядро проблемы состоит в том, что этот код Java оценивается как false, потому что ZERO имеет scale 0 и новый BigDecimal имеет ненулевую шкалу:

BigDecimal.ZERO.setScale(3).equals(BigDecimal.ZERO)

Ответ 2

<c:if test="${someBigDecimal.compareTo(BigDecimal.ZERO) == 0}">

Ответ 3

<c:if test="${someBigDecimal eq 0}">

Ответ 4

В последней версии EL (поддерживаемой Tomcat 7, например) вы можете попробовать:

<c:if test="${someBigDecimal.doubleValue() == 0}">

Ответ 5

Вы можете попробовать функцию signum:

<c:if test="#{someBigDecimal.signum() == 0}">