Validating dates in spring form objects

Validating dates on a form managed by Spring is a bit more tricky than checking a simple string attribute for emptiness.

You can use the org.springframework.format.annotation.DateTimeFormat annotation on the field that you would like to validate. This annotation has an attribute called pattern that allows you to set a the pattern to validate against. Example usage of the annotation:

public class PostForm {
    
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @NotNull(message = "Please provide a date.")
    private Date date;
    
    private String contents;
    
    // getters and setters...
}

So far it was similar to using other validation annotations. However, you might notice that this annotation does not have a message attribute, so you can’t specify what message should be printed. Let’s see what error message we get back if we use the annotation. I used 2014-99-11 as the date and yyyy-MM-dd as the pattern to validate against.

Failed to convert property value of type java.lang.String to 
required type java.util.Date for property date; 
nested exception is org.springframework.core.convert.ConversionFailedException: 
Failed to convert from type java.lang.String to type @org.springframework.format.annotation.DateTimeFormat 
@javax.validation.constraints.NotNull java.util.Date for value 2014-99-11; 
nested exception is java.lang.IllegalArgumentException: Unable to parse 2014-99-11

You can see that this results in not too nicely looking error message that explains what is the problem in detail…but users may expect a bit more concise message.

To override the default message, you need to have a messageSource and in that a message with a specific key that corresponds to the validated attribute.

Our message source is set up like this in the application context:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <value>classpath:i18n/messages</value>
    </property>
</bean>

Of course we have a messages.properties file in the i18n folder under our classpath. Our messages.properties file looks like this:

typeMismatch.postForm.date=Please enter a valid date.

The name of the message key is very important. It is structured like this: {ValidationClass}.{modelObjectName}.{field}. You don’t necessarily need to specify the whole key, because the resolving happens in the following way in our case:

  1. First the typeMismatch.postForm.date key is looked up.
  2. If it is not found, the typeMismatch.postForm key is looked up.
  3. If it is not found, the typeMismatch key is looked up.
  4. If it is not found, the default message will be rendered.

Download

You can download the source code of an example application here.