如何从自定义@FacesConverter中读取配置属性?
问题描述
我编写了如下JSF转换器类:
@FacesConverter("imixsDateConverter") public class ImixsDateConverter implements Converter { private static final String DEFAULT_DATE_FORMAT_PATTERN = "dd.MM.yyyy"; private static final String DEFAULT_TIME_ZONE = "CET"; // Set the timezone to CET @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null || value.trim().isEmpty()) { return ""; // Convert empty string to null } component.get try { String pattern = DEFAULT_DATE_FORMAT_PATTERN; String timezone = DEFAULT_TIME_ZONE; DateFormat dateFormat = new SimpleDateFormat(pattern); dateFormat.setTimeZone(TimeZone.getTimeZone(timezone)); return dateFormat.parse(value); } catch (ParseException e) { throw new RuntimeException("Error converting date", e); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (value == null || "".equals(value)) { return ""; // Convert null to empty string } if (value instanceof Date) { String pattern = DEFAULT_DATE_FORMAT_PATTERN; String timezone = DEFAULT_TIME_ZONE; DateFormat dateFormat = new SimpleDateFormat(pattern); dateFormat.setTimeZone(TimeZone.getTimeZone(timezone)); return dateFormat.format((Date) value); } else { throw new IllegalArgumentException("Invalid value type: " + value.getClass().getName()); } } }
现在我想通过以下两种方式为其配置timeZone、pattern等属性:
方式一:
<h:inputText value="#{workitem.item[item.name]}"> <f:converter converterId="imixsDateConverter" timeZone="#{message.timeZone}" pattern="#{message.datePatternShort}" /> </h:inputText>
方式二:
<h:inputText value="#{workitem.item[item.name]}"> <f:converter converterId="imixsDateConverter"> <f:attribute name="pattern" value="#{message.datePatternShort}" /> <f:attribute name="timeZone" value="#{message.timeZone}" /> </f:converter> </h:inputText>
但我无法读取这些属性,尝试过使用:
Map<Object, Object> map = context.getAttributes();
和:
Map<String, Object> map = component.getAttributes();
页面中定义的属性并未包含在这些属性映射中,请问如何访问这些自定义属性?
解决方案
针对你使用的两种配置方式,分别对应不同的属性读取方法:
方式一:直接在<f:converter>标签上添加属性
这种方式要求转换器类必须提供对应的成员变量和setter方法,JSF会自动将标签上的属性值注入到转换器实例中。
修改转换器类,添加pattern和timeZone成员变量(覆盖默认值),并提供setter:
@FacesConverter("imixsDateConverter") public class ImixsDateConverter implements Converter { private String pattern = "dd.MM.yyyy"; // 默认值 private String timeZone = "CET"; // 默认值 // 提供setter方法,JSF自动注入属性值 public void setPattern(String pattern) { this.pattern = pattern; } public void setTimeZone(String timeZone) { this.timeZone = timeZone; } @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null || value.trim().isEmpty()) { return null; // 建议返回null而非空字符串,符合JSF规范 } try { DateFormat dateFormat = new SimpleDateFormat(this.pattern); dateFormat.setTimeZone(TimeZone.getTimeZone(this.timeZone)); return dateFormat.parse(value); } catch (ParseException e) { throw new RuntimeException("Error converting date", e); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (value == null) { return ""; } if (value instanceof Date) { DateFormat dateFormat = new SimpleDateFormat(this.pattern); dateFormat.setTimeZone(TimeZone.getTimeZone(this.timeZone)); return dateFormat.format((Date) value); } else { throw new IllegalArgumentException("Invalid value type: " + value.getClass().getName()); } } }
配置完成后,JSF会自动把标签上的pattern和timeZone值注入到转换器字段中,直接使用即可。
方式二:使用<f:attribute>标签传递属性
这种方式下,<f:attribute>是绑定到组件(此处为h:inputText)上的,需要通过component.getAttributes().get("属性名")读取值,若未配置则使用默认值。
修改转换器的方法如下:
@Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null || value.trim().isEmpty()) { return null; } // 从组件属性中获取配置值,无配置则用默认值 String pattern = (String) component.getAttributes().getOrDefault("pattern", "dd.MM.yyyy"); String timeZone = (String) component.getAttributes().getOrDefault("timeZone", "CET"); try { DateFormat dateFormat = new SimpleDateFormat(pattern); dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone)); return dateFormat.parse(value); } catch (ParseException e) { throw new RuntimeException("Error converting date", e); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (value == null) { return ""; } if (value instanceof Date) { String pattern = (String) component.getAttributes().getOrDefault("pattern", "dd.MM.yyyy"); String timeZone = (String) component.getAttributes().getOrDefault("timeZone", "CET"); DateFormat dateFormat = new SimpleDateFormat(pattern); dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone)); return dateFormat.format((Date) value); } else { throw new IllegalArgumentException("Invalid value type: " + value.getClass().getName()); } }
注意:如果属性值是EL表达式(如#{message.datePatternShort}),JSF会自动解析并返回实际值,无需手动处理。
额外注意事项
- 原代码中
getAsObject方法存在语法错误:component.get未完成,需修正。 - 原代码中
getAsObject返回空字符串"",建议改为返回null,符合JSF转换器规范。
内容的提问来源于stack exchange,提问作者Ralph
相关产品推荐
相关产品推荐

