Date Validation in Spring MVC
I am using Spring MVC (Spring 2.5.1) and needed date validation in my form, with a custom error message. Reflecting my inability to R(or find)TFM, I failed miserably to find a resource that clearly outlined how to set up validation for a date. So here is my public record of a small saga.
First, I set up a date field in my JSP.
<form:errors cssClass="error" path="document.publishDate"/> <form:input id="publishDate" path="document.publishDate" cssStyle="width:100px;" />
There is a matching java.util.Date
instance variable called publishDate
in my Document
class.
Next step is to define an object that can validate my dates. In servletName-servlet.xml
, I have defined a custom date editor.
<bean id="customDateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor"> <constructor-arg > <bean class="java.text.SimpleDateFormat"> <constructor-arg><value>dd/MM/yyyy</value></constructor-arg> </bean> </constructor-arg> <constructor-arg ><value>true</value></constructor-arg> </bean>
The same config file defines my controller, and I inject the custom data editor into the controller through my Spring config.
<!-- Controller for ... --> <bean name="doJob.htm" id="jobController" class="..." ... <property name="customDateEditor" ref="customDateEditor"/> ... </bean>
This means that my controller will have an instance of CustomDateEditor ready to use, injected by Spring. I could have had my controller create its own CustomDateEditor, however. Either way, the next step is to register the data editor in the initBinder(HttpServletRequest, ServletRequestDataBinder)
method of my controller.
/** * {@inheritDoc} * @see org.springframework.web.servlet.mvc. * BaseCommandController#initBinder(javax.servlet.http.HttpServletRequest, * org.springframework.web.bind.ServletRequestDataBinder) */ protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { binder.registerCustomEditor(Date.class, getCustomDateEditor()); }
The controller needs to be a subclass of org.springframework.web.servlet.mvc.BaseCommandController
to have an initBinder()
method. In this instance, my controller is a org.springframework.web.servlet.mvc.SimpleFormController
.
This means that I have automatically defined the date format required for all dates that get validated by this controller.
Next step is to set up the error message I want. Personally, I found this the hardest part. I had to look at my logging closely to work out what was going on. In my controller's showForm(HttpServletRequest, HttpServletResponse, BindException, Map)
method, I was outputting the result of a toString()
call on the BindException
object and I saw the following. The key things are in red.
Field error in object 'viewDocCommand' on field 'document.publishDate': rejected value [noWayIsThisAGoodDateValue!]; codes [typeMismatch.viewDocCommand.document.publishDate, typeMismatch.document.publishDate,typeMismatch.publishDate, typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [viewDocCommand.document.publishDate,document.publishDate]; arguments []; default message [document.publishDate]]; default message [Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property 'document.publishDate'; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "noWayIsThisAGoodDateValue!"]
After a lot of searching in forums and javadocs I finally accumulated enough hints to get a hunch! Those dot separated values are message keys. Spring looks in the messages.properties
file to find values to replace them with. I put entries into messages.properties
to cover the most generic error type (typeMismatch.java.util.Date
) and the field name.
typeMismatch.java.util.Date={0} is an invalid date. Use format DD/MM/YYYY. document.publishDate=Publish Date
Now when I have a bad date value, I see the error message: Publish Date is an invalid date. Use format DD/MM/YYYY.
Links that helped me with this.
Comments
If I add the method manually, how do I get the CustomDateEditor injected? If I have to manually construct the CustomDateEditor in the controller, then why put it in the app-servlet.xml?
Any help much appreciated.
Rebeccah
Feel free to not post my previous question.
Rebeccah
http://forum.springframework.org/showthread.php?t=18335
My post got some responses, and it turns out that it's not a good idea to put PropertyEditors in application-servlet.xml and inject them, because they are not thread safe (they maintain state information). However, someone else has followed up asking what about if you set the bean scope to "request" scope. I'll be interested to see how that discussion ends up.
Rebeccah
I've noticed that it catches the previous error only if the current value from the form is TypeMismatchError (in this case is Date)
Steps to produce errors:
1. First – user enters future date 12/12/2009 – this is violate the rule which is developer defined validation.
System displays error message “Cannot enter future Date”
2. Second - user enters wrong date format 04/31/2008
System display 2 errors messages:
one for TypeMisMatchError (spring binding validation )
and developer defined error in this case “Cannot enter future Date” from previous submit.
3. Third – user blanks out the date field
System displays only one error message “Date is required field – Enter Date”
How can I clear out the previous errors?
thanks
Anh