@FacesConverter(forClass = Clazz.class) 和 p:calendar

@FacesConverter(forClass = Clazz.class) and p:calendar

基本 Joda 时间转换器(代码对于本线程的上下文来说绝对是多余的):

@Named
@ApplicationScoped
@FacesConverter(forClass = DateTime.class)
public class DateTimeConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null || value.isEmpty()) {
            return null;
        }

        try {
            return DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa Z").parseDateTime(value).withZone(DateTimeZone.UTC);
        } catch (IllegalArgumentException | UnsupportedOperationException e) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Message"), e);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value == null) {
            return "";
        }

        if (!(value instanceof DateTime)) {
            throw new ConverterException("Error");
        }

        try {
            return DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa Z").print(((DateTime) value).withZone(DateTimeZone.forID("zoneId")));
        } catch (IllegalArgumentException e) {
            throw new ConverterException("Error", e); // Not required.
        }
    }
}

为什么它不能与使用 converter 属性明确指定的 <p:calendar> unless/until 一起使用?

<p:calendar converter="#{dateTimeConverter}" value="{bean.dateTimeValue}" .../>

与其他组件一样,无需提及 converter 属性即可正常工作,因为转换器装饰有

@FacesConverter(forClass = DateTime.class)

<p:calendar>不支持此功能吗?

使用 PrimeFaces 5.2 和 JSF 2.2.12。

如果 class 有转换器,则基于 5.2 CalendarRenderer#encodeEnd(), it uses CalendarUtils#getValueAsString() to obtain the value for output. It indeed doesn't consult via Application#createConverter(Class)

51          //first ask the converter
52          if(calendar.getConverter() != null) {
53              return calendar.getConverter().getAsString(context, calendar, value);
54          }
55          //Use built-in converter
56          else {
57              SimpleDateFormat dateFormat = new SimpleDateFormat(calendar.calculatePattern(), calendar.calculateLocale(context));
58              dateFormat.setTimeZone(calendar.calculateTimeZone());
59              
60              return dateFormat.format(value);
61          }

这证实了您观察到的行为。您最好向 PrimeFaces 人员创建一个问题报告,请求添加一个 instanceof Date 检查,在相反的情况下,通过 class 从应用程序中获取转换器,如下所示:

Converter converter = context.getApplication().createConverter(value.getClass());
if (converter != null) {
    return converter.getAsString(context, calendar, value);
}
else {
    throw new IllegalArgumentException(value.getClass());
}                    

考虑到 Java8 的 java.time API 的使用越来越多,这确实有意义。顺便说一下,在 CalendarRendererCalendarUtils 中还有其他一些地方实现了这个 could/should(并且他们实际上正在执行 instanceof 检查,但没有将其委托给转换器 class,如果有的话)。