Date fields in forms using Spring and AppFuse

I had some problems getting date fields to work (and return a friendly error message) so here comes a little documentation for future reference. This was in an AppFuse based Spring Framework project.

The model contains a java.util.Date property and simply exposing it as usual in a form will cause an exception since Spring doesn’t know how to convert the string into a Date:

Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property startTime; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [java.util.Date] for property startTime: no matching editors or conversion strategy found

To solve this we need a custom property editor. It may be registered by overriding the initBinder() method of a controller. Spring already contains a CustomDateEditor that we may use for this purpose.

protected void initBinder(HttpServletRequest request, 
                          ServletRequestDataBinder binder) {
    SimpleDateFormat dateFormat =
        new SimpleDateFormat(getText("date.format", request.getLocale()));
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, null, new CustomDateEditor(dateFormat, true));
}

Note that you may replace the getText() call with a hard-coded “yyyy-MM-dd” or similar, at least for debugging purposes.

If it is an AppFuse project and the controller extends BaseFormController then you don’t need this since the CustomDateEditor is already registered in the BaseFormController.initBinder() method.

Now it should work, however, the error message isn’t especially user-friendly when entering an invalid date:

Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property startTime; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: “2008-37-09”

Better error messages may be provided using the resource file of the application (make sure you have a ResourceBundleMessageSource set up) by specifying typeMismatch error message for this type:

typeMismatch.java.util.Date={0} is an invalid date.

The {0} will be replaced by the property name, in this case startTime, which may not be desired. This may be overridden by setting a custom error message for this specific property:

typeMismatch.startTime=Start time is an invalid date.

Do also make sure to update validation.xml accordingly.