1

問題:JSFを介してBigDecimalをフォーマットする必要がありますが、JSFは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);
  }
}

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を取得するために値に対して「newBigDecimal(double)」を呼び出すよりも、DoubleではなくStringに変換するBigDecimal値を取得していたようです-これは間違った値を返します。


修正:これを解決する1つの方法は、次のコードを使用することです。

@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);
  }
}

しかし、それは私にはハックのように思えます。

これを修正するためのアイデアとその背後にある理由。ありがとう。

4

1 に答える 1

2

理想的には、これは「丸め」属性がある場合はf:convertNumberを介して実行されますが、そうではありません。

これを行うためのクリーンな方法は、独自のラウンドアップf:converterクラスを作成し、ELメソッド呼び出しを使用する代わりにXHTMLで適切な場所にf:converterタグを使用することです。コンバーターは値をオブジェクト、つまりBigDecimalとして取得し、それ自体を文字列に変換する役割を果たします。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>
 * &lt;h:outputText value="#{EL}"&gt;
 *  &lt;f:converter id="com.edsi.jsf.RoundHalfUp"/&gt;
 *  &lt;f:attribute name="decimalPlaces" value="2"/&gt;
 * &lt;/h:outputText&gt;
 * <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();
    }

}
于 2013-02-04T04:25:07.427 に答える