Integrating Spring MVC 3.0 with JSR 303 (aka javax.validation.*)

Annotated POJO validation comes to a JDK near you!

The new annotated validation spec (jsr 303) is pretty slick, especially when used along side Spring MVC 3.0, and when backed by ejb3 entities. I’m pretty impressed with how easily it integrates with Spring MVC’s framework, and with how seamlessly error messages are passed to the form taglibs so they show up in your web forms.

I know some of you might argue that the current validation framework might not address complex validations, but after giving Hibernate’s reference implementation documentation a look, it seems interdependent validations are at least possible through embedded @Valid in complex objects. Even if you have to come up with your own really weird validation for a particular field, jsr 303/hibernate offers a way to create your own custom annotation driven validations. For the remaining 95% of all the other web forms, you’re probably going to be alright if you use the pre-defined validations offered by jsr 303.

Getting started

Download the jsr 303 reference implementation jars from SourceForge, via Hibernate’s download page. You’ll need to add the main, Hibernate validator jar (currently hibernate-validator-4.0.2.GA.jar as of 2/8/2009) and the included jars in the release jar’s lib directory to your application’s classpath if they’re not already there (if you’re on jboss 5.1, probably at least validation-api-1.0.0.GA.jar, maybe more). The Hibernate reference implementation release also includes the jar files required to run in a jdk 5 runtime, include those if you’re not running on jdk 6. Download Spring MVC from Spring’s download page, its part of the Spring 3.0 release. Spring MVC requires the following jars in your classpath:

    • org.springframework.asm
    • org.springframework.beans
    • org.springframework.context
    • org.springframework.context-support
    • org.springframework.core
    • org.springframework.expression
    • org.springframework.web
    • org.springframework.web.servlet

Wiring Spring MVC

You’ll need to make sure you map Spring MVC correctly. Consider the following in web.xml:

	<!-- Spring Action Servlet -->
	<servlet>
		<servlet-name>spring</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				/WEB-INF/spring-servlet.xml
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>*.sf</url-pattern>
	</servlet-mapping>

And then in spring-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context">
		
	<!-- Scans the class path of this application for @Components to deploy -->
	<context:component-scan base-package="com.faceroller.web" />
	
	<context:annotation-config/>

	<bean id="multipartResolver" 
	class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

	<!-- flags annotations for processing -->
	<mvc:annotation-driven />

	<!-- forward "/" requests -->
	<mvc:view-controller path="/" view-name="welcome"/>

	<!-- Configures Handler Interceptors -->	
	<mvc:interceptors>
	<!-- Changes the locale when a 'locale' request parameter is sent -->
	<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
	</mvc:interceptors>

	<!-- Saves a locale change using a cookie -->
	<bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver" 
		id="localeResolver" />

	<!-- hey man, I like my jsp files in "/". WEB-INF just seems.. ugly -->
	<bean 
	  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	  <property name="viewClass" 
			value="org.springframework.web.servlet.view.JstlView"/>
	  <property name="prefix" value="/"/>
	</bean>
	
	<bean 
	  class="org.springframework.context.support.ResourceBundleMessageSource"
	  id="messageSource">  
		<property name="basename" value="messages" />
	</bean>  
	
</beans>

Now that we’ve squared away the setup, on with the examples:

Example ejb3 jsr-303 validation equipped entity bean

import javax.persistence.*;
import javax.validation.Valid;

@Entity
@Table(name="tb_inventory")
public class InventoryItem implements Serializable {

	private static final long serialVersionUID = 1L;
	
	@Id  
	@GeneratedValue(strategy=GenerationType.IDENTITY) 
	protected int id;
	
	@NotNull
	protected BigDecimal price = new BigDecimal("0.00");	
	
	@NotEmpty(message = "Name is a required field")
	protected String name;
	
	@Min(100)
	protected int minimumPrice;

	@Email
	private String mail;

	@Pattern(regexp="[a-z]+")
	private String lowerCaseName;
	
	@Future
	private Date futureDate;

	@AssertTrue
	private boolean mustBeTrue;

	@OneToMany
	@JoinTable(name="tb_order_items_to_images")
	@Valid
	protected List<InventoryImage> images = new ArrayList<InventoryImage>();
	
	
	// setters/getters here...
}

Lets examine the annotations:

@NotNull

@NotNull flags the annotated field as valid only if it has a value assigned. A String with a null value will fail, while a String with a “” value will pass. Since the “message” parameter is not defined, the error message will default to whatever the validation package ships with. In this case, I think the message will read “name is a required field”.

@NotEmpty(message = “Name is a required field”)

@NotEmpty flags the annotated field as valid if the field is both not null and not a value of “”. Since the “message” parameter is defined for this annotation, the param value will replace the default message passed into spring mvc’s error framework.

@Min(100)

@Min flags the field as valid only if it has a value equal to or higher than the value in the parens. The contrary to this is @Max, which will flag as valid values lower than the value in the parens.

@Email

@Email flags the field as valid only if the field is a valid email.

@Pattern(regexp=”[a-z]+”)

@Pattern will flag the field as valid only if the string matches the regular expression passed in as the parameter. In this case it will only pass if the string is made up only of lowercase letters.

@Future

@Future will flag as valid only if the date annotated is in the future. The contrary to this is @Past, which would be valid only if the date has already passed.

@AssertTrue

@AssertTrue will flag as valid if the annotated boolean resolves to true. The contrary to this is @AssertFalse, which will flag as valid only if the boolean resolves to false.

@Valid

@Valid will validate only if the complex object annotated validates as true. Lets say in this case that InventoryImage has two validation annotated fields; if any InventoryImage fails either of those two fields, then the enclosing InventoryItem will fail validation because of the @Valid annotation. This is how compelx cross object validations are supported, other than defining your own.

Now that we’ve annotated our bean, we’ll need to hook it into a Spring MVC controller.

The Spring MVC Controller

package com.faceroller.web;

@Controller
@RequestMapping("/inventory")
public class InventoryController {

	private static Log log = LogFactory.getLog(InventoryController.class);
	
	/**
	 * initialize the form
	 *
	 */
	@RequestMapping("/add/setup.go")
	public ModelAndView addInventorySetup(InventoryItem item){
		
		log.info("setup add inventory");
		return new ModelAndView("/inventory/add.jsp", "item", item);
	}

	/**
	 * process the form
	 *
	 */
	@RequestMapping(value="/add/meta.go", method=RequestMethod.POST)
	public String processInventoryMeta(
			@ModelAttribute("item") @Valid InventoryItem item, 
			BindingResult result) {
		
		log.info("process add inventory");
		
		if (result.hasErrors()) {
			return "/inventory/add.jsp";
		}

		InventoryService service = ServiceLocator.getInventoryService();
		service.addInventoryItem(item);
		
		return "redirect:/add/images/"+item.getId();
	}
	
	/**
	 * forward to whatever page you want
	 *
	 */	
	@RequestMapping("/browse/item/{itemId}")
	public ModelAndView getInventoryItem(@PathVariable int itemId){

		log.info("getting item");

		InventoryService service = ServiceLocator.getInventoryService();
		InventoryItem item = service.getInventoryItemById(itemId);

		return new ModelAndView("/inventory/browse.item.jsp", "item", item);
	}
	
}

Pay special attention to

	@RequestMapping(value = "/add/meta.go", method=RequestMethod.POST)
	public String processInventoryMeta(
			@ModelAttribute("item") @Valid InventoryItem item, 
			BindingResult result) 

You’ll notice @Valid marked up right before the InventoryItem item bean parameter. This is the annotation that does all the validation magic for us. There is no need to implement a custom validator factory, as spring mvc’s framework would normally require. If the bean fails validation, BindingResult result will be prepopulated with all corresponding JSR 303 validation errors. The catch is you have to add the @ModelAttribute(“item”) annotation to the signature, otherwise the form bean in the jsp will not have access to all the error messages passed along by the validations.

The jsp code

<form:form method="post" commandName="item" action="/process/form">
<table width="100%" border="0">
	<tr><td colspan="3" class="bottomPadding">
		<span class="secionHeader">Add item to inventory</span>
	</td></tr>
	<tr><td class="labelColumn" width="100">
		Price 
	</td><td width="100">
		<form:input path="price"/>
	</td><td>
		<form:errors path="price" cssClass="error"/>
	</td></tr>
	<tr><td class="labelColumn">
		Name
	</td><td>
		<form:input path="name"/>
	</td><td>
		<form:errors path="name" cssClass="error"/>
	</td></tr>
</table>
</form:form>

This is just a simple form, nothing new here, but I’m including for completeness. The Spring MVC framework will correctly populate the form tags with any bean errors should the form fail validation. The form tags are part of the standard spring taglibs, found in the org.springframework.web.servlet.* jar included in the Spring 3.0 distribution.

EDIT:
Stuart Gunter pointed out in a comment to this post that there is a workaround for injecting your own messages using spring’s autowiring. Click the jump for his example.

Resources
Hibernate 4.x Validation reference implementation
Spring MVC 3.0 documentation



Related posts:

  1. Quartz Scheduled Jobs – v1.5.2
  2. Java, XML and XStream
  3. Manually override and launch quartz jobs…

Comments (43)

  1. avatar

    6:41 am, February 12, 2010craig  / Reply

    nice, thanks.

  2. avatar

    4:28 am, February 15, 2010Todd  / Reply

    Thanks for the example. It’s great. Just an FYI, I couldn’t get this to work on Google App Engine until after I upgraded to 1.3.1. Not sure if it was user error, but my error messages started popping up after that.

    • avatar

      5:03 am, February 15, 2010Ant  / Reply

      Hi Todd, thanks for the comment. Yeah – it seems that Google Apps Engine does something funky with form beans as of spring 2.5.x behind closed doors. I found this google support thread that discusses that specific problem in more detail. I can’t speak with authority but it would appear from your experience that GAE 1.3.1 might address it. I’m glad it wound up working for you, I really like how the two mesh together.

  3. avatar

    7:55 pm, February 17, 2010Karthik  / Reply

    I see an issue with Spring MVC using @Valid annotation though since you cannot specify the JSR 303 validation ‘group’ that you want to validate. Consider the case of a wizard like flow where the same model object is populated across several steps. Specifying @Valid will trigger the validation on default group and some of the fields might not be relevant to a particular step in the wizard like workflow. and I don’t want to use Spring web flow :)

    • avatar

      8:02 pm, February 17, 2010Ant  / Reply

      That’s an interesting case. I’m going to try and look at this and see what I can come up with.

  4. avatar

    3:03 pm, April 15, 2010chris marx  / Reply

    im wondering the exact same thing too (specifying a group), any ideas?

  5. avatar

    11:33 pm, May 26, 2010Gary  / Reply

    I’m new to Spring MVC. I have a question. Suppose user entered “3.3xy” for price. Obviously, there’s no way the price field will be populated by a valid value. Upon returning back to the user, how can the jsp page show “3.3xy” using (form:input path=”price”)? Or will user input on price field be lost?

    • avatar

      11:08 am, June 4, 2010Ant  / Reply

      Hi Gary,
      I didn’t see anything in the hibernate documentation that specifically mentioned echoing the data back to the input form. In the Hibernate Validator section 3.1.3 though, we find out we can write our own custom messages, and there might be a way to echo the value if we could only get a handle on the input value if its supported. The validation required value is marked as {value}. Maybe it supports {input}? Otherwise I’m afraid we’ll have to write out own message interpolator.

  6. avatar

    6:42 am, July 1, 2010jl  / Reply

    When I try to write the code as described in part “pay special attention to” I only get an error message claiming that anotation type is not applicable to this kind of declaration. Can anyone assist me with this?

    • avatar

      10:50 am, July 1, 2010Ant  / Reply

      Sounds like you’re using the hibernate @Valid annotation, make sure you are using the javax.validation.Valid as your import and not the hibernate @valid annotation. They’re slightly different and do not mean the same thing.

  7. avatar

    7:47 am, July 7, 2010elle  / Reply

    Great post!

    But how about depended validation in the same object class, say like ZipCode can’t be null if Country is given, otherwise it is not mandatory to give Country? This would be Address class.

  8. avatar

    2:57 am, July 14, 2010jaanlai  / Reply

    Here is my problem also brought up in Spring Forum:

    am using my own tag to go trought all the error messages like this:

    However, this is not working right at all with my javax.validation anotations in my object class. I am only getting the constraint as error message, like with @NotEmpty the message shown is NotEmpty and so on.

    I have tried to put the message on object class like:
    @NotEmpty (message=”You got an error here”)

    and codes:
    @NotEmpty (message=”{error.code}”)

    with defining the codes and translations in ValidatorMessages/messages.properties.

    I have also tried forming the code like:

    NotEmpty.myClass.MyProperty

    but the result is always the same. To me it seems like the error code is different with javax. Can you help me with this please?

    • avatar

      11:02 am, July 14, 2010Ant  / Reply

      Theres a section in the hibernate validator documentation that goes over custom messages and how to write them:

      http://docs.jboss.org/hibernate/validator/4.0.1/reference/en/html/validator-usingvalidator.html#section-message-interpolation

      If you correctly placed your custom messages at the base of your classpath, you’ll want to make sure that properties file is written correctly – take a look at the bundled resources used by default as a guide, here are some examples:

      org.hibernate.validator.constraints.NotEmpty.message=may not be empty
      org.hibernate.validator.constraints.Range.message=must be between {min} and {max}
      javax.validation.constraints.Pattern.message=must match “{regexp}”

      Notice the different message bundle property names. You’ll want to stick to how they named their message references if you want to preserve the correct message links to display properly. You can find all the resource bundled properties in the hibernate validator jar file:

      hibernate-validator-4.0.2.GA.jar?org\hibernate\validator\ValidationMessages.properties
      hibernate-validator-4.0.2.GA.jar?org\hibernate\validator\ValidationMessages_de.properties
      hibernate-validator-4.0.2.GA.jar?org\hibernate\validator\ValidationMessages_fr.properties

      Parsing curly brackets used in the annotated validations like “@NotEmpty (message=”{error.code}”)” would require a re-implementaion of the spring/hibernate integration code that would add functionality to try and map messages dynamically using the notation you attempted. You might want to look at implementing your own message interpolater (http://docs.jboss.org/hibernate/validator/4.0.1/reference/en/html/validator-bootstrapping.html) which should be able to plug into the spring framework and might cover what you’re trying to do.

      Hope this helps

      – a

  9. avatar

    4:41 pm, July 20, 2010Julien  / Reply

    I had this : to my applicationContext.xml, but my BindingResult always has 0 error. I don’t know understand…

    How should be configure the spring context?

    • avatar

      5:30 pm, July 20, 2010Ant  / Reply

      I’m not sure I understand what you mean by the BindingResult always has 0. The spring mvc configuration should be set up as a normal spring application, it’s no different. The only difference is adding the hibernate validator jars to the classpath and annotating the validations, and of course annotating @Valid for your validation. Can you explain a little more what the trouble is?

      - a

      • avatar

        4:02 pm, July 21, 2010Julien  / Reply

        Sorry, I didn’t explain well my problem. First I’m in a portlet environment. For detecting hibernate validator, I wrote this in my context :

        And for my method I’m doing this :

        protected void registration(@Valid Patient patient,
        BindingResult result) {
        if (result.hasErrors()) {
        return;
        }
        }

        But my result never has errors, even if my form is empty. I think that I missed something.

        • avatar

          11:17 am, July 23, 2010Ant  / Reply

          Can you post your class definition for Patient? It sounds like whatever validation annotations you’re using are not being parsed in or loaded up. Try doing a single annotation first and step through your code to make sure the BindingResult result variable has errors – if it does then your jsp isn’t displaying correctly (try adding @ModelAttribute(“patient”) before @Valid to provide scope ) and if it doesn’t then double check your annotations to make sure they’re set up correctly.

  10. avatar

    8:23 am, July 21, 2010Stuart Gunter  / Reply

    As a response to the comments about group validation. I’m not sure if anyone has mentioned it already, but Spring Web Flow does handle subset validation for scenarios where you want to validate parts of the object at various stages (e.g. in a wizard).

    Have a look here for more details: http://static.springsource.org/spring-webflow/docs/2.1.x/reference/html/ch05s10.html

    • avatar

      10:24 am, July 21, 2010Ant  / Reply

      Thanks for the heads up!

  11. avatar

    7:55 am, July 23, 2010Stefan Haberl  / Reply

    Hi,

    For those of you who want to integrate Hibernate Validator with Spring and want to generate a custom message:

    A workaround I’m quite happy with is to wire your Spring MessageSource into your custom Validator like so:

    @Autowired
    private MessageSource messageSource;

    and then manually resolve the error message:

    Locale locale = LocaleContextHolder.getLocale();
    String message = messageSource.getMessage(“key”, new Object[] { “Test” },
    locale);

    context.disableDefaultConstraintViolation();

    context.buildConstraintViolationWithTemplate(message).addConstraintViolation();

    HTH

    • avatar

      11:52 pm, July 25, 2010Ant  / Reply

      Thanks for the workaround, I’ll point to your workaround in the article.

    • avatar

      1:39 pm, October 6, 2010dejanmr  / Reply

      It is easy enough to use convention in your message files. Ie.

      Email.mail=My custom message.

      Spring gives you a choice of codes, so you can have your custom messages out of the box.

      If you debug through errors form result, you can see choice of codes to use in your message file, flexible enough to be used as general code, or specific to view.

      • avatar

        2:12 pm, October 6, 2010dejanmr  / Reply

        Even

        Email=My custom bad email message
        Size=My custom size must be between {0} and {1}

        etc. will do

  12. avatar

    10:17 am, August 16, 2010Tomasz Minkowski  / Reply

    Hello,

    Excellent tutorial, thanks.

    However, I have the same problem as Julien.

    I seem to get everything according to the tips, but my binding result object does not contain any errors (I catch it on debug mode and I’m pretty sure my annotations are correct)

    Seems like spring is ignoring the @Valid annotation… how can I possibly debug it? How to check whether Spring does indeed invoke the validation routine?

    Thanks

    • avatar

      12:12 pm, August 16, 2010Ant  / Reply

      Ive run into a similar problem when I crossed @Valid annotations. Is it mapped to javax.validation.Valid and not org.hibernate.validator.Valid?

      • avatar

        1:17 pm, August 16, 2010Tomasz Minkowski  / Reply

        Yes I mapped it to

        javax.validation.Valid

        Should it be the hibernate one?

        What jar does org.hibernate.validator.Valid belong to?
        It does not seem to be a part of

        hibernate-validator.jar

        Thanks very much for the reply!

    • avatar

      2:40 pm, August 16, 2010Ant  / Reply

      Nope, that’s the correct annotation, should be mapping to javax.validation.Valid. You should not be using any of the org.hibernate.validator.* annotations, mixing annotations like that will cause validation to go inert as you’re describing.

      The best way to check it while debugging is to enter some known values that fail validation, and verify that BindingResult has errors – maybe try something like a single field validation, and work your way up towards more complex validations. What kind of setup are you using, and what kind of validations are you trying to validate?

      • avatar

        2:46 pm, August 16, 2010Tomasz Minkowski  / Reply

        I’m trying but a simple form, submitting empty values while having @NotEmpty, @NotNull, @Min, @Size and other annotations on the command object.

        According to what I’ve read, the @Valid should be picked up when hibernate-validator is in the classpath. My problem is that I have no way of checking that this happens.

        I have given up and I will implement the Validator interface and use @InitBinder.

        Thanks,

    • avatar

      1:01 pm, August 26, 2010Flavouski  / Reply

      This seems to be happening for Portlet people. Ends up the functionality with mvc: annotation-driven won’t work quite as expected for us until Spring 3.1 M1:

      https://jira.springframework.org/browse/SPR-6817

      • avatar

        2:38 pm, August 26, 2010Ant  / Reply

        Thanks, I’m sure this will solve the mystery for some folks.

  13. avatar

    11:33 am, August 17, 2010Russ  / Reply

    I believe that this line also needs to be present in the applicationContext.xml for the application to initialize validation when started.

    <mvc:annotation-driven/>

    • avatar

      11:44 am, August 17, 2010Ant  / Reply

      Good point, I’ll make a note of this.

  14. avatar

    4:43 am, February 7, 2011TripLeM  / Reply

    Thanks for the hint with the @ModelAttribute, see http://javafreedom.org/blog/?p=356.

    You saved us quite some time ;-)

    • avatar

      11:47 am, February 7, 2011Ant  / Reply

      No problem, glad to have helped!

  15. avatar

    5:39 pm, February 9, 2011TripLeM  / Reply

    Hm, if you would like to skip the @ModelAttribute Annotation, it is possible as well, but then the modelMap needs to contain the object name in CamelCase (e.g. “testObject” and not “testobject”). This works as well.

  16. avatar

    2:25 am, March 21, 2011Ogun  / Reply

    dear sir, thanks for this article.

    i can not use spring’s tag lib.
    i want to show error-message to my JSP page by using JSTL and expression language (el).

    tell me how to do that please.

  17. avatar

    9:32 am, September 27, 2011Chris  / Reply

    Thanks a lot for your article. You saved me some time figuring out why Spring doesn’t show error messages in the web view…

  18. avatar

    2:32 am, September 24, 2012tarang  / Reply

    hi
    i am doing exactly the same.

    public String loginprocess( HttpServletRequest request, HttpServletResponse response, @ModelAttribute(“user”) @Valid User user, BindingResult result,Model model) { //processes the user information from the login page
    if(result.hasErrors())
    {
    System.out.println(“in side login process has errors “);

    return “public/welcome”;
    }

    but even if i submit correct input, the page gets redirected to public/welcome , although the error messages are being displayed correctly.

    plz help me out.

    • avatar

      11:36 am, October 11, 2012Ant  / Reply

      I would suggest you step through and debug all the errors in result, as that would be the reason it redirects you to “public/welcome”. Check your validation annotations as it’s likely you’re validating something you aren’t expecting. It could also be that your user model attribute is missing fields, or has the wrong data type or something else. Use the error messages to guide you.

  19. avatar

    7:59 am, February 25, 2013ArunM  / Reply

    Thank you for getting me started on bean validation

  20. avatar

    8:41 am, May 24, 2013Rao.Sampangi  / Reply

    The example is good.. it resolved my validation issue. Thanks for information.