Spring Framework, JSR-303 Validation and Custom Messages

   Posted by: Jim White

By Jim White (Director of Training and Instructor)

In Minnesota where Intertech is located, spring comes a little later that in other parts of the country.  This year, I noticed our flowering trees finally came out in full force this week.  ?Bout time!  It seemed very fitting that I spent the week teaching Spring 3 to a great group of people.

On the last day of class, I got a question from Michelle that I wasn?t able to answer as it was at the very end of our class.  She wanted to know how to customize the error message displayed on validation errors triggered by JSR-303 annotations in beans.  Great question and I want to use this post to provide her a proper answer that I didn?t get a chance to provide.

Spring 3 and JSR-303 Bean Validation API

As of Spring 3.0, the framework fully supports the JSR-303 Bean Validation API.  JSR-303 standardizes validation and allows you to declare validation constraints on bean properties via annotation.  An example of a bean annotated with some validation constraints (@Size, @NotNull, @Past, @Min, @Max) is shown below.

   1: public class Contact {
   2:     private Long id = 0L;
   3:     @Size(min = 1)
   4:     private String firstName;
   5:     @NotNull
   6:     @Size(min = 1)
   7:     private String lastName;
   8:     @Past
   9:     private Date dateOfBirth;
  10:     private boolean married;
  11:     @Min(0)
  12:     @Max(20)
  13:     private int children;
  14:     ...
  15: }

For more information about JSR-303 and the bean validation API, see here.  You can also find a good tutorial blog on some of the annotations here.

Custom Error Messages

Michelle?s question centered on how to provide a custom error message on a JSP that uses a bean like Contact as its command bean.  A default message is displayed when a property if found in violation of the constraint.  For example, here is the form to edit/add a Contact.

   1: <form:form action="addcontact.request" method="post"
   2:     commandName="contact">
   3:     <table border="1">
   4:         <tr>
   5:             <th>&nbsp;</th>
   6:             <th><spring:message code="editcontact.heading"/></th>
   7:         </tr>
   8:         <tr>
   9:             <td bgcolor="cyan"><spring:message code="editcontact.label.firstname"/></td>
  10:             <td><form:input path="firstName" size="40" /><font
  11:                 color="#FF0000"><form:errors path="firstName*" /></font></td>
  12:         </tr>
  13:         <tr>
  14:             <td bgcolor="cyan"><spring:message code="editcontact.label.lastname"/></td>
  15:             <td><form:input path="lastName" size="40" /><font
  16:                 color="#FF0000"><form:errors path="lastName*" /></font></td>
  17:         </tr>
  18:         <tr>
  19:             <td bgcolor="cyan"><spring:message code="editcontact.label.dob"/></td>
  20:             <td><form:input path="dateOfBirth" size="40" /><font
  21:                 color="#FF0000"><form:errors path="dateOfBirth*" /></font></td>
  22:         </tr>
  23:         <tr>
  24:             <td bgcolor="cyan"><spring:message code="editcontact.label.married"/></td>
  25:             <td><form:checkbox path="married" /><font color="#FF0000"><form:errors
  26:                 path="married" /></font></td>
  27:         </tr>
  28:         <tr>
  29:             <td bgcolor="cyan"><spring:message code="editcontact.label.children"/></td>
  30:             <td><form:input path="children" size="5" /><font
  31:                 color="#FF0000"><form:errors path="children*" /></font></td>
  32:         </tr>
  33:         <tr>
  34:             <td><input type="submit" value="<spring:message code="editcontact.button.save"/>" /></td>
  35:             <td><input type="reset" value="<spring:message code="editcontact.button.reset"/>" /></td>
  36:         </tr>
  37:     </table>
  38:     <a href="index.jsp"><spring:message code="editcontact.link.mainpage"/></a>
  39: </form:form>

Without any changes to the defaults, the error messages displayed on the form are less than pleasing.image

Option 1 ? add a message parameter to the annotation

The first option to correcting this issue and providing your own custom error message is to add a message parameter to the validation annotations.  Some sample error messages are shown in the code below along with a picture of the same form using those messages.

   1: public class Contact {
   2:     private Long id = 0L;
   3:     @Size(min = 1, message="Contact first name is required.")
   4:     private String firstName;
   5:     @NotNull(message="Contact cannot be left empty.")
   6:     @Size(min = 1, message="Contact last name is required.")
   7:     private String lastName;
   8:     @Past(message="Contact date of birth must be a date in the past.")
   9:     private Date dateOfBirth;
  10:     private boolean married;
  11:     @Min(value=0, message="A contact cannot have fewer than 0 children")
  12:     @Max(value=20, message="A contact cannot have more than 20 children")
  13:     private int children;
  14:     ...
  15: }

image

Option 2 ? Use the Message Bundle

While providing custom messages right in the bean with the validations is convenient, you may elect to use the custom messages in your applications message resource bundles.  Using a resource bundle allows your application support internationalization/localization concerns.

To setup an application to use resource message bundles, add the following bean to your Spring bean configuration file.

   1: <bean id="messageSource"
   2:     class="org.springframework.context.support.ResourceBundleMessageSource">
   3:     <property name="basenames">
   4:         <list>
   5:             <value>messages</value>
   6:         </list>
   7:     </property>
   8: </bean>

In this example, the default message bundle file would be messages.properties (located somewhere on the application?s classpath).

You can override the default validation annotation messages in the messages.properties by specifying the annotation and the new default message as shown below.

   1: #example messages.properties
   2: #override @Size default message
   3: Size=Your must provide an entry.
   4: #override @Min default message
   5: Min=Your entry is too small.
   6: #override @Max default message
   7: Max=Your entry is too large.
   8: #override @Past default message
   9: Past=Your entry must be a date in the past.

image

This is nice, but you will notice that the messages are not very custom to the context.  Since the same annotation may be used in multiple locations (i.e. on multiple beans), the message must be kept fairly generic.

You can further customize the messaging and still keep it external to the code by using dot notation with the property and/or command bean name and property to further specify which message to use from the bundle.  In the example below, messages specific to firstName and lastName fields are provided while also providing more specific contact bean date of birth and children messages.

   1: #example messages.properties
   2: #override @Size default message
   3: Size.firstName=First names cannot be empty.
   4: Size.lastName=Last names cannot be empty.
   5: #override @Min default message
   6: Min.contact.children=You must specify a number of children >= 0.
   7: #override @Max default message
   8: Max.contact.children=You must specify a number of children <= 20.
   9: #override @Past default message
  10: Past.contact.dateOfBirth=Birth dates must be a date in the past.

image

My thanks to Michelle for providing an excellent question.  Hope this helps Michelle and others looking to customize JSR-303 validation messages in Spring.

Need Spring Training?

If you or someone you work with could benefit from Spring 3 training, please visit our web site and sign up today for Complete Spring 3 Framework.  You can also contact Dan McCabe ? head of training sales ? at DMcCabe@intertech.com.


Comments (2)

Nokia Asha 303 1/9/2012 4:07 AM

I m glad to read thiz post…

Ninju Bohra 5/4/2012 3:54 PM

Hello,

I am using Spring 3.1.0.RC1 (along with hibernate validator 4.2.0)  and I am trying to provide very contextual messages for the standard validation (i.e. different message for different attributes) -- very similar to what you are doing in your last example, but it is not working.

I am successfully using a custom resource bundle file.

Which classes in the Spring Framework are involved in the process so that I can debug the flow ?

Thanx,

Ninju Bohra

Add a Comment

*

*

Loading

Find Us
Contact Us 651-288-7000 1-800-866-9884
Home | Training | Curriculum | Course Finder | Schedule | Enroll | Twin Cities Java User Group | Consulting | Foundation | Jobs | About Us | Our Story | Press Room | Instructors | President | Map & Directions | Sitemap

Java Training | JSF / Struts / Spring / Hibernate Training | Java Power Tools Training | .NET 4.0 & Visual Studio 2010 Training | Microsoft Web Development Training | Prism / MVVM / MEF Training | .NET 3.5 and Visual Studio 2008 Training | .NET 2.0 and Visual Studio 2003 Training | Cloud Computing Training | Ajax / Web Services / XML Training | Groovy and Grails Training | SQL Server 2012 Training | SQL Server 2008 Training | SQL Server 2005 Training | Mobile Development Training | SharePoint 2010 Training | SharePoint 2007 Training | Agile, Process, Analysis & Design Training | Arch/Design Patterns Training | Microsoft Official Curriculum Training | Web Development Training | Ruby Training | Rational Application Developer (RAD) Training | WebSphere Application Server Training | WebSphere Portal Training | WebLogic Training | Boot Camp Training | Project Management Training | C / C++ Training | Metro / WinRT / Windows 8 Development Training | Retired

Intertech delivers training on-site and virtually serving cities including Phoenix, AZ | San Francisco, CA | Los Angeles, CA | San Diego, CA | San Jose, CA | Washington, DC | Chicago, IL | Orlando, FL | Boston, MA | Duluth, MN | Minneapolis St. Paul, MN | Rochester, MN | Raleigh-Durham, NC | New York, NY | Philadelphia, PA | Austin, TX | Dallas, TX | Houston, TX | Seattle, WA.