【问题标题】:JSF converter with null value具有空值的 JSF 转换器
【发布时间】:2016-02-11 18:16:10
【问题描述】:

我需要将java.math.BigDecimal 类型的null 属性值转换为0.00,在任何地方都有指定的小数位数(仅用于显示(<h:outputText>),因此不适用于输入组件)。

下面给出了预期完成这项工作的基本转换器(为简洁起见,货币、百分比、区域设置等已完全排除在外)。

@FacesConverter("bigDecimalConverter")
public final class BigDecimalConverter implements Converter {

    private static final int SCALE = 2;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {

        if (submittedValue == null || submittedValue.isEmpty()) {
            return null;
        }

        try {
            return new BigDecimal(submittedValue).setScale(SCALE, RoundingMode.HALF_UP).stripTrailingZeros();
        } catch (NumberFormatException e) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Message"), e);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object modelValue) {

        BigDecimal value;

        if (modelValue == null) { // This is expected to replace null with 0.
            value = BigDecimal.ZERO;
        } else if (modelValue instanceof Long) {
            value = BigDecimal.valueOf((Long) modelValue);
        } else if (modelValue instanceof Double) {
            value = BigDecimal.valueOf((Double) modelValue);
        } else if (!(modelValue instanceof BigDecimal)) {
            throw new ConverterException("Message");
        } else {
            value = (BigDecimal) modelValue;
        }

        NumberFormat numberFormat = NumberFormat.getNumberInstance();
        numberFormat.setGroupingUsed(true);
        numberFormat.setMinimumFractionDigits(SCALE);
        numberFormat.setMaximumFractionDigits(SCALE);
        return numberFormat.format(value);
    }
}

使用如下输出组件引用java.math.BigDecimal 类型的关联模型或bean 的属性。

<h:outputText value="#{bean.value}">
    <f:converter converterId="bigDecimalConverter"/>
</h:outputText>

bean.value 是托管 bean 中的 java.math.BigDecimal 类型。如果bean.valuenull,则不会调用getAsString() 方法。因此,在预期值为零的地方呈现空输出。

value="#{bean.value}" 需要更改为value="#{empty bean.value ? 0 : bean.value}",转换器才能执行其相关任务。

然而,在任何地方都将这个条件测试放在 EL 中是非常不利于维护的。

有没有办法调用getAsString() 方法,当目标属性是null 时,有条件地尝试在该方法中将其设置为0 (BigDecimal.ZERO)?


更新:

getAsString() 方法通过 &lt;o:param&gt; (OmniFaces) 调用。

<h:outputFormat value="Discount ({0}%)">
    <o:param value="#{bean.value}">
        <f:converter converterId="bigDecimalConverter"/>
    </o:param>
</h:outputFormat>

#{bean.value}返回null时,转换器转换后显示Discount (0.00%)

【问题讨论】:

  • 提供 JSF impl-version 会很有用。
  • 它是 Mojarra 2.2.12。在 Apache Tomcat 8.0.27.0、GlassFish 4.1 和 WildFly 10.0.0 上交替测试。

标签: jsf converter bigdecimal


【解决方案1】:

这是特定于 Mojarra 的。出现此问题的原因是当值为 null 时未调用转换器(请参阅source here)。我在 MyFaces 实现中测试了相同的代码,结果是转换总是被调用,无论值是否为空(可以看到 here,第 378 行)。

因此,如果不能选择更改 JSF 实现,我认为通过 OmniFaces 的解决方案就足够了。在最坏的情况下,维护一个像 #{convert(bean.value)} 这样进行转换的函数可能会让您的视图比内联比较更清晰。

【讨论】:

  • OmniFaces 推荐什么方法来防御这个特定问题?
  • OmniFaces 有自己的implementation of paramo:param,无论值为空,它也会调用转换器。因此,您可以使用此组件进行转换,如您在问题更新中演示的那样。但是如果你想要一个简单的转换来显示它的值,我认为像#{bean.convertNullAsZero(bean.value)}这样的函数会更简单、更清楚地完成这项工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 2012-12-26
  • 2013-06-13
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
相关资源
最近更新 更多