问题:需要通过JSF格式化BigDecimal,但JSF正在破坏BigDecimal的精度。
JSF:
<h:outputText value="#{webUtilMB.roundUp(indexPrice.percentage, 2)}"/>
爪哇:
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);
}
}
在WebUtilManagedBean.roundUp方法中有一个断点显示我'dbvalue'是'1.3249999999999999555910790149937383830547332763671875'而不是'1.325'。
然后我重载了WebUtilManagedBean中的roundUp方法:
public Double roundUp(Double dvalue, int scale){
System.out.println(dvalue);
}
在这个重载方法中有一个断点时让我感到惊讶的是: - 'dvalue'是'1.325',这是正确的。 - 实际调用的方法不是roundUp(BigDecimal,int)方法。
我后来尝试使用BigDecimal构造函数,结果如下:
BigDecimal db1 = new BigDecimal("1.325"); -> 1.325
BigDecimal db2 = new BigDecimal(1.325d); -> 1.3249999999999999555910790149937383830547332763671875
理论:从上面看,似乎JSF将我的BigDecimal值转换为String而不是Double,而不是在值上调用'new BigDecimal(double)'来获取BigDecimal - 它返回错误的值
修复:解决此问题的一种方法是使用以下代码:
@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);
}
}
但这对我来说似乎是个黑客。
有关解决此问题及其背后原因的任何想法。感谢。
答案 0 :(得分:2)
理想情况下,这可以通过f:convertNumber完成,如果它有'rounding'属性,但它没有。
执行此操作的干净方法是编写自己的roundup f:converter类,并在XHTML中使用适当的f:converter标记,而不是使用EL方法调用。您的转换器将获取作为Object的值,即BigDecimal,并负责将其转换为String本身。请参阅f:converter的文档。令人惊讶的是JSF没有正确地做到这一点,但我想一旦你进入EL方法调用,一切都是一个字符串。这样的事情(警告:未经测试):
import java.math.BigDecimal;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
/**
* Use via e.g.:
* <pre>
* <h:outputText value="#{EL}">
* <f:converter id="com.edsi.jsf.RoundHalfUp"/>
* <f:attribute name="decimalPlaces" value="2"/>
* </h:outputText>
* <pre>
* @author Esmond Pitt
*/
@FacesConverter(value="com.edsi.jsf.RoundHalfUp")
public class RoundHalfUpConverter implements Converter
{
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
BigDecimal bd = (BigDecimal)value;
int decimalPlaces;
try
{
decimalPlaces = Integer.parseInt((String)component.getAttributes().get("decimalPlaces"));
}
catch (Exception exc)
{
decimalPlaces = 2; // or whatever
}
return bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).toString();
}
}