You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从自定义@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会自动解析并返回实际值,无需手动处理。

额外注意事项

  1. 原代码中getAsObject方法存在语法错误:component.get未完成,需修正。
  2. 原代码中getAsObject返回空字符串"",建议改为返回null,符合JSF转换器规范。

内容的提问来源于stack exchange,提问作者Ralph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:23:11