Problem: Need to format a BigDecimal through JSF, but JSF is destroying the precision of the BigDecimal.
JSF:
<h:outputText value="#{webUtilMB.roundUp(indexPrice.percentage, 2)}"/>
Java:
public class IndexPrice {
public BigDecimal getPercentage(){ return new BigDecimal("1.325"); }
}
@ManagedBean("webUtilMb")
public class WebUtilManagedBean{
public BigDecimal roundUp(BigDecimal dbvalue, int scale){
return dbvalue.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
}
}
Having a break point in the WebUtilManagedBean.roundUp method showed me ‘dbvalue’ is ‘1.3249999999999999555910790149937383830547332763671875’ and not ‘1.325’.
I then overloaded the roundUp method in WebUtilManagedBean with:
public Double roundUp(Double dvalue, int scale){
System.out.println(dvalue);
}
What surprised me when having a break point in this overloaded method was:
– ‘dvalue’ is ‘1.325’, which is correct.
– the method actually got called instead of the roundUp(BigDecimal, int) method.
I later experimented with the BigDecimal constructor, with the following result:
BigDecimal db1 = new BigDecimal("1.325"); -> 1.325
BigDecimal db2 = new BigDecimal(1.325d); -> 1.3249999999999999555910790149937383830547332763671875
Theory: From the above, it seems that JSF was taking my BigDecimal value converting it to String, than to Double, than calling a ‘new BigDecimal(double)’ on the value to get the BigDecimal – which returns the wrong value.
Fix: One way to resolve this is to use the following code:
@ManagedBean("webUtilMb")
public class WebUtilManagedBean{
public Double roundUp(Double dvalue, int scale){
return this.roundUp(**new BigDecimal(dvalue.toString())**, BigDecimal.ROUND_HALF_UP);
}
public BigDecimal roundUp(BigDecimal dbvalue, int scale){
return dbvalue.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
}
}
But that just seems like a hack to me.
Any ideas on fixing this and the reasons behind it. Thanks.
Ideally this would be done via f:convertNumber if it had a ’rounding’ attribute, but it doesn’t.
The clean way to do this would be to write your own roundup f:converter class, and use an f:converter tag where appropriate in the XHTML instead of using the EL method call. Your converter will get the value as an Object, i.e. a BigDecimal, and is responsible for converting it to a String itself. See the documentation for f:converter. Surprised that JSF doesn’t do this correctly but I guess once you get into EL method calls everything is a String. Something like this (warning: untested):