The following does not always behave as you would expect:
<c:if test="${someBigDecimal == 0}">
If someBigDecimal has a value of 0, but has a scale other than 0, the == operation returns false. That is, it returns true when someBigDecimal is new BigDecimal("0"), but false when someBigDecimal is new BigDecimal("0.00").
This results from the JSP 2.0, 2.1, and 2.2 specifications, which state:
For <, >, <=, >=:
If A or B is BigDecimal, coerce both A and B to BigDecimal and use the return value of A.compareTo(B).
For ==, !=:
If A or B is BigDecimal, coerce both A and B to BigDecimal and then:
- If operator is ==, return A.equals(B)
- If operator is !=, return !A.equals(B)
This means the ==
and !=
operators result in a call to the .equals()
method, which compares not only the values, but also the scale of the BigDecimals. The other comparison operators result in a call to the .compareTo()
method, which compares only the values.
Of course, the following would work:
<c:if test="${not ((someBigDecimal < 0) or (someBigDecimal > 0))}">
But this is rather ugly, is there a better way to do this?
In JSP 2.2 EL and above this expression will evaluate to true
:
${someBigDecimal.unscaledValue() == 0}
This will avoid any loss of precision but assumes that someBigDecimal
is always of type BigDecimal
.
A custom EL function is probably the best approach for older versions of EL:
${fn:isZero(someBigDecimal)}
The core of the problem is that this Java code evaluates to false
because ZERO
has a scale of 0
and the new BigDecimal
has a non-zero scale:
BigDecimal.ZERO.setScale(3).equals(BigDecimal.ZERO)