String 使用JSF转换器输出时,用指定值替换空字符串或空字符串
下面是一个转换器,主要用于修剪前导和尾随空格,并用单个空格替换句子或文本中单词之间的多个空格。转换器现在被修改为将String 使用JSF转换器输出时,用指定值替换空字符串或空字符串,string,jsf,null,converter,String,Jsf,Null,Converter,下面是一个转换器,主要用于修剪前导和尾随空格,并用单个空格替换句子或文本中单词之间的多个空格。转换器现在被修改为将null或空字符串替换为“不可用”(如果需要,可以动态本地化) 由于未调用转换器,因此当模型值基于com.sun.faces.renderkit.html_basic.textrender时,当关联模型中的属性值为null时,扩展了com.sun.faces.renderkit.html\u basic.textrender以调用转换器 public final class Html
null
或空字符串替换为“不可用”(如果需要,可以动态本地化)
由于未调用转换器,因此当模型值基于com.sun.faces.renderkit.html_basic.textrender
时,当关联模型中的属性值为null
时,扩展了com.sun.faces.renderkit.html\u basic.textrender
以调用转换器
public final class HtmlBasicRenderer extends TextRenderer {
@Override
public String getCurrentValue(FacesContext context, UIComponent component) {
if (component instanceof UIInput) {
Object submittedValue = ((UIInput) component).getSubmittedValue();
if (submittedValue != null) {
return submittedValue.toString();
}
}
return getFormattedValue(context, component, getValue(component));
}
}
已删除条件测试,因此即使遇到null
值,也可以调用getFormattedValue()
方法
Object currentObj = getValue(component);
if (currentObj != null) {
currentValue = getFormattedValue(context, component, currentObj);
}
这已在faces config.xml
中注册,如下所示
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.Text</renderer-type>
<renderer-class>com.example.renderer.HtmlBasicRenderer</renderer-class>
</renderer>
</render-kit>
在该方法中getFormattedValue()
因此,
需要用,
if (currentValue == null) {
converter = Util.getConverterForClass("".getClass(), context);
return converter == null ? "" : converter.getAsString(context, component, currentValue);
}
(需要建议)。首先,
转换器从来不会强制执行“默认值”
不管问题是什么,无论您在getAsString()
中执行什么操作,您都应该保证当您通过getAsObject()
将结果字符串传回时,可以将其转换回原始对象。你的转换器不能做到这一点。尽管您不太可能使用它,但从技术上讲,转换器需要修改,以便将确切的字符串“notavailable”
转换回null
。换句话说,转换器的设计必须确保getAsObject()
和getastring()
能够在无限循环中成功地传递彼此的结果,并每次返回相同的结果
至于强制默认值的具体功能要求,您应该在模型或视图中执行,而不是在转换器中执行,这取决于实际默认值来自何处。在您的特定情况下,您只需要在用户界面中没有默认占位符文本/标签的情况下就可以了。这属于视图
在整个应用程序中的任何地方都使用EL-like{empty bean.value?'Not available':bean.value}
进行条件测试都是愚蠢的
我完全同意,如果你已经开发了一半的应用程序,而且到处都有数百个这样的应用程序,那么这就是疯狂。然而,如果你从一开始就考虑到这一点,那就不是疯狂。如果您没有这样做,那么好吧,吸取教训,咬紧牙关,并定期相应地修复代码。体面的IDE具有基于正则表达式的查找和替换功能,这有助于实现这一点。每个人都去过那里,做过那种疯狂的事,甚至我自己。要简化样板文件,请将其包装在EL函数或标记文件中
至于当模型值为null
时,转换器
未被调用的具体问题,我个人完全同意这是意外行为,这曾被报道为。由于它导致了测试用例失败,所以它后来被命名为WONTFIX,毕竟最好作为JSF规范问题报告。这是按照(已经在JSF1.2中)完成的。我在上面检查了MyFaces2.2.9,它也不会触发转换器,因此暴露了相同的规范问题
然而,技术问题是可以理解的。null
值没有合理的getClass()
,因此无法通过值的类以这种方式查找转换器。仅当转换器在组件上显式注册时,它才起作用
<h:outputText value="#{bean.potentiallyNullValue}" converter="stringTrimmer" />
然而,当我自己在这里尝试时,还是失败了。结果是,当值是String
的实例时,将完全跳过converter by class。仅当转换器在组件上显式注册时,它仍然有效。这很可能是JSF 1.2实现过程中的一个疏忽(在此版本之前,String.class
的转换器根本不受支持,此问题只针对解码而非编码进行了修复)
这可以在相同的自定义渲染器中被覆盖(使用上面的getValue()
override)和下面的getFormattedValue()
覆盖,从而显式查找转换器
@Override
protected String getFormattedValue(FacesContext context, UIComponent component, Object currentValue) throws ConverterException {
Converter converter = ((UIOutput) component).getConverter();
if (converter == null) {
converter = context.getApplication().createConverter(currentValue.getClass());
}
return super.getFormattedValue(context, component, "".equals(currentValue) ? null : currentValue, converter);
}
请注意,您不需要检查UIInput
,因为您已经在javax.faces.Output
/javax.faces.Text
组件族/类型上明确注册了自定义呈现程序(即,它将仅在
组件上运行)
尽管如此,最好的解决方案仍然是为此创建EL函数或标记文件
<h:outputText value="#{empty bean.value ? 'Not available' : bean.value}" />
如果只是在outputText中,您在哪个组件中尝试此操作(因为您将其创建为通用的forClass=String.class
),我会使用simpleCustom组件并用它搜索/替换默认的jsf或primeFaces组件。它基本上是
。可以为选定的可选字段创建自定义组件,但需要仔细记住哪些字段可能包含null或空值。好吧,您可以隐式地声明(通过使用'forClass=String.class')每根绳子都是这样?那就不需要记忆了。始终使用自定义的
;-)到处使用自定义组件?我使用带有转换器的
组件,如
,
。因此,它需要根据目标
组件所引用的模型值类型创建不同的自定义组件。getFormattedValue()
中的currentValue
值可以在任何时候为null
。因此,如果currentValue
为null
,则currentValue.getClass()
将在渲染器本身中抛出java.lang.NullPointerException
。如果重写getValue,则不会抛出(
<h:outputText value="#{bean.potentiallyNullValue}" converter="stringTrimmer" />
@Override
protected Object getValue(UIComponent component) {
Object value = super.getValue(component);
return (value != null) ? value : "";
}
@Override
protected String getFormattedValue(FacesContext context, UIComponent component, Object currentValue) throws ConverterException {
Converter converter = ((UIOutput) component).getConverter();
if (converter == null) {
converter = context.getApplication().createConverter(currentValue.getClass());
}
return super.getFormattedValue(context, component, "".equals(currentValue) ? null : currentValue, converter);
}
<h:outputText value="#{empty bean.value ? 'Not available' : bean.value}" />
<h:outputText value="#{of:coalesce(bean.value, 'Not Available')}" />
<h:outputText value="#{of:coalesce(bean.value, i18n.na)}" />
<h:outputText value="#{your:value(bean.value)}" />
<your:text value="#{bean.value}" />