问题
Basic Joda Time converter (the code is absolutely superfluous for the context of this thread) :
@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.
}
}
}
Why does it not work with a <p:calendar>
unless/until it is explicitly specified by using the converter
attribute?
<p:calendar converter="#{dateTimeConverter}" value="{bean.dateTimeValue}" .../>
Like other components, it is expected to work without mentioning the converter
attribute because the converter is decorated with
@FacesConverter(forClass = DateTime.class)
Is this feature not supported by <p:calendar>
?
Using PrimeFaces 5.2 and JSF 2.2.12.
回答1:
Based on 5.2's CalendarRenderer#encodeEnd(), it uses CalendarUtils#getValueAsString() to obtain the value for output. It indeed doesn't consult via Application#createConverter(Class) if there's a converter by 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 }
That confirms the behavior you observed. You'd best create an issue report to PrimeFaces guys which requests adding an instanceof Date
check in place, and in the opposite case obtain the converter by class from the application something like below:
Converter converter = context.getApplication().createConverter(value.getClass());
if (converter != null) {
return converter.getAsString(context, calendar, value);
}
else {
throw new IllegalArgumentException(value.getClass());
}
This would indeed make sense given the increasing use of Java8's java.time
API. There are by the way a few other places in CalendarRenderer
and CalendarUtils
where this could/should be implemented (and where they are actually performing an instanceof
check, but not delegating it to the converter by class, if any).
来源:https://stackoverflow.com/questions/31598697/facesconverterforclass-clazz-class-and-pcalendar