空值的JSF转换器

问题描述:

我需要将java.math.BigDecimal类型的属性值转换为0.00,并将其指定为小数点后的位置(仅用于显示(<h:outputText>),因此不适用于输入组件)。空值的JSF转换器

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

@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的豆的特性。

<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这是有条件地尝试在方法(BigDecimal.ZERO)设置为0


更新:

getAsString()方法被调用与<o:param>(OmniFaces)。

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

这将显示Discount (0.00%)之后已经由所述转换器转换,当#{bean.value}返回null

+0

提供JSF impl-version会很有用。 –

+0

这是Mojarra 2.2.12。测试Apache Tomcat 8.0.27.0,GlassFish 4.1和WildFly 10.0.0 final。 – Tiny

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

所以如果改变JSF实现不是一个选项,我认为通过OmniFaces的解决方案已经足够好了。在最坏的情况下,保持一个功能,使像#{convert(bean.value)}这样的转换可能比内联比较更清晰您的视图。

+0

OmniFaces推荐什么方式来抵御这个特殊问题? – Tiny

+0

OmniFaces有自己的[param的实现](https://github.com/omnifaces/omnifaces/blob/master/src/main/java/org/omnifaces/component/output/Param.java#L120),[ o:param](http://showcase.omnifaces.org/components/param),它也会调用转换器,无论该值为null。所以你可以使用这个组件进行转换,就像你在问题更新中演示的那样。但是如果你想要一个简单的转换来显示它的值,我认为像'#{bean.convertNullAsZero(bean。价值)}'会更简单明确地完成工作。 –