del.icio.us Digg DZone Reddit StumbleUpon
Annotation-Based Validation with the Spring Bean Validation Framework - Willie Wheeler
« Previous | 1 | 2 | 3

Servlet and Spring Configuration

Here's our completely standard web.xml:

Code listing: /WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    
    <servlet>
        <servlet-name>contact</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>contact</servlet-name>
        <url-pattern>/contact/*</url-pattern>
    </servlet-mapping>        
</web-app>

Though I said I'm assuming you already know Spring WebMVC, I'll just point out that since I didn't specify a custom location for the application context file, I have to put it at /WEB-INF/contact-servlet.xml. If you want the file to live elsewhere, or if you want it to be associated with the servlet context instead of the DispatcherServlet, you'll have to set that up in web.xml accordingly.

Here's the Spring application context:

Code listing: /WEB-INF/contact-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
    <!-- Enable annotation-based validation using Bean Validation Framework -->
    <!-- Using these instead of vld namespace to prevent Eclipse from complaining -->
    <bean id="configurationLoader"
        class="org.springmodules.validation.bean.conf.loader.annotation
.AnnotationBeanValidationConfigurationLoader"/>
    <bean id="validator" class="org.springmodules.validation.bean.BeanValidator"
        p:configurationLoader-ref="configurationLoader"/>
    
    <!-- Load messages -->
    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource"
        p:basenames="errors"/>

    <!-- Discover POJO @Components -->
    <!-- These automatically register an AutowiredAnnotationBeanPostProcessor -->
    <context:component-scan base-package="contact"/>
    
    <!-- Map logical view names to physical views -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:prefix="/WEB-INF/"
        p:suffix=".jsp"/>
</beans>

(IMPORTANT: In the configurationLoader definition, make sure you put the class name on a single line. I had to break it up for formatting purposes.)

If you're not familiar with it, I'm using the p namespace here for syntactic sugar—it allows me to specify properties using a nice shorthand.

The first two beans basically create the BeanValidator instance we're going to use. It turns out that instead of defining these two beans explicitly, you can use a special element from a special namespace:

  • namespace is xmlns:vld="http://www.springmodules.org/validation/bean/validator";
  • purported schema location is http://www.springmodules.org/validation/bean/validator-2.0.xsd;
  • element is <vld:annotation-based-validator id="validator"/>

But when I do it, Eclipse complains (even though the code works when you run it) since there isn't at the time of this writing actually an XSD at the specified location. (At least there's a JIRA ticket for it.) So I'll just use the two beans for now.

The other stuff is mostly normal Spring WebMVC stuff. I put the message source on the app context, scan for the controller (which is why I'm autowiring the validator into the controller), and put a view resolver on the context too.

Finis

Build and deploy your WAR, and then point your browser to your web app; for example:

http://localhost:8080/contact-example/contact/form

Try submitting the form with empty fields, or an invalid e-mail address, or fields that are too long. If things are working correctly, you ought to see error messages and even field highlighting when validation fails.

And that, my friends, is it! Feel free to post a comment if you run into problems getting it to work and I'll try to help if I can.

Again, if you want to download the sample code (minus dependencies; see above), here it is:

Have fun!

Social bookmarks: del.icio.us Digg DZone Reddit StumbleUpon
« Previous | 1 | 2 | 3

Comments (40)

Thanks for the tutorial. Very helpful!!!!
By Donny A. Wijaya on Jul 17, 2008 at 11:53 AM PDT
Congratulation, this tutorial will help many people
By spcmdr on Jul 18, 2008 at 6:31 AM PDT
I despise writing validators, so I'm really pleased to learn about this - thanks!
By DM on Jul 18, 2008 at 7:05 AM PDT
Really nice and sharp. I am new to spring and this article really helped me to understand.
Thanks.
By Rishi on Jul 27, 2008 at 1:31 PM PDT
Thanks for the article, I've posted some follow-up questions here:

http://forum.springframework.org/showthread.php?p=194050#post194050
By domurtag on Jul 30, 2008 at 4:22 PM PDT
You rock, buddy!
very useful post - thanks man!
By Oleg on Aug 6, 2008 at 1:11 AM PDT
Thanks everybody for the nice comments. It's great to get them. :-)

DM, I'm with you. I hate writing them too. When I found out about the BVF I was pretty happy. Almost makes writing validation code fun...?
By Willie Wheeler on Aug 6, 2008 at 8:12 PM PDT
Thanks for the tutorial. Very helpful
But... how do i use it with WEBFLOW 2?
By Diego on Oct 7, 2008 at 8:39 AM PDT
Hi Willie,

Do you know how to enable client (javascript) validation from the same code? Is it possible?

Thanks,

Derek
By Derek Lin on Oct 13, 2008 at 3:23 PM PDT
Hi Willie,

How do you check something only when it's NOT blank? For example, when you enter email, email is ok, but when you enter invalid.email, an error is thrown.

Thanks,

Derek
By Derek Lin on Oct 13, 2008 at 4:41 PM PDT
Hi Derek. Commons-Validator and Valang support client-side validation. I don't think BVF does though I'm not 100% sure on that. See

https://springmodules.dev.java.net/docs/reference/0.9/html/validation.html

As far as your second question--if I understand it correctly, you want the e-mail to be optional, but if it's provided then it needs to be a valid e-mail address, right? The first thing to check is whether that's actually the behavior of @Email. It may be. (I haven't checked.) If not, then in the worst case you could write a custom ValidationRule over it.
By Willie Wheeler on Oct 13, 2008 at 8:28 PM PDT
Hi Willie,

I am trying Valang since the annotated validation doesn't seem sufficient.

Thanks for posting these articles!

-- Derek
By Derek Lin on Oct 14, 2008 at 10:53 AM PDT
Willie,

You can use the following to validate the email entry (only if the field is not blank);

@Email(applyIf = "email is not blank")

Regards

Tuncay
By Tuncay on Oct 17, 2008 at 1:13 PM PDT
Tuncay, that's great to know--thanks!
By Willie Wheeler on Oct 17, 2008 at 7:48 PM PDT
A great tutorial. Thanks for posting it.

Incidentally, I think that the annotation based bean validation may work better for non-Pojo Controllers if you add a @Validatable annotation to the UserMessage class
By Jeff Oh on Oct 30, 2008 at 10:22 PM PDT

If you have UserMessageForm which extends UserMessage class, would the validation still happen when passed to validator?

In my case, I had few more properties which cannot be put in the model form. I could have either declared them as @Transient in the model object, instead i choose to have a new object extending the base object. When the instance of UserMessageForm was passed to Validator to validate, it went to infinite loop.

Can someone explain me whats happening here?

Thanks.

By Harish on Mar 17, 2009 at 4:11 AM PDT

Hi,

I initialized the validator bean in *-servelet.xml, but then i got SEVERE error saying couldnot find the bean

then after reading through the log I put it in applicationContext.xml and then it works

So are the beans loaded from servelet.xml or applicationContext.xml??

Thanks, Sawan

By sawan on Mar 17, 2009 at 6:11 AM PDT

@Sawan

Maybe I'm just pointing the obvious but the file must be named *-servlet.xml not "servelet".

Or was it just a typo?

By Pablo on Mar 31, 2009 at 7:13 AM PDT

Good article,it's very helpful!

would you please provide us a printable version?

thx!

By leomodo on May 5, 2009 at 8:34 PM PDT

@leomondo: At some point I plan to do that, though probably not til after I finish the book. Thanks though for the feedback.

By Willie Wheeler on May 5, 2009 at 9:58 PM PDT

By Diego on 2008-10-7 at 8:39 ?? PDT Do you know how to enable client (javascript) validation from the same code? Is it possible? Actually i have the same question when i directly add the code from standard example:

<%@ taglib prefix="validator"
    uri="http://www.springmodules.org/tags/commons-validator"%>
<validator:javascript formName="quiz" staticJavascript="false" /> 

but i got an error state that bean named "validatorFactory " is missing, but after i add the definition in my configuration like as follows

<bean id="validatorFactory"
    class="org.springmodules.validation.commons.DefaultValidatorFactory">
    <property name="validationConfigLocations">
        <list>
            <value>/WEB-INF/validator-rules.xml</value>
        </list>
    </property>
</bean> 

The annotated validation previously worked well failed!(i use hibernate validation instead of common validation annotation and customised validator according to this guide: link text

Can anyone give any hint? Thanks, david

By david on May 11, 2009 at 2:55 AM PDT

does anyone get such an exception?

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personCommand' defined in file [C:\Program Files\Apache Software Foundation\Apache Tomcat 6.0.18\webapps\Journal\WEB-INF\classes\com\softservecom\training\commands\PersonCommand.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.softservecom.training.commands.PersonCommand]: Constructor threw exception; nested exception is java.lang.Error: Unresolved compilation problems: NotBlank cannot be resolved to a type Length cannot be resolved to a type The attribute max is undefined for the annotation type Length NotBlank cannot be resolved to a type Length cannot be resolved to a type The attribute max is undefined for the annotation type Length

eclipse doesn`t show any errors until deployment timed

By Vlad on May 16, 2009 at 4:16 AM PDT

all my questions and requirements is discussed in the following furum: any one intereted too can keep an eye on that progress:

https://forum.hibernate.org/viewforum.php?f=26

By david on May 17, 2009 at 11:17 PM PDT

This is the most complete and proper implementation of the Data Binding and Validation of the HTML Forms in spring,Kudos to Willie Wheeler for such a nice illustration and Thanks a TON.

By midas on Jul 27, 2009 at 6:28 AM PDT

Hey Thanks, i was puzzling for long on how to use validation from spring.

But still i have one problem is running @CascadeValidation, i have just added one more field in the UserMessage class as @CascadeValidation private Address address;

but BeanValidator is not validating this class even after wrong values are set in to it.

Any suggestion and help is greatly appreciated

By vikas on Sep 5, 2009 at 1:10 PM PDT

Thanks for the article willie. I have been able to run Spring annotations just cos' of you. However I get nullpointerexception

//--

java.lang.NullPointerException springmvc.web.CarNewController.onSubmit(CarNewController.java:139) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:421) org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:136) org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:326) org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:313) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511) javax.servlet.http.HttpServlet.service(HttpServlet.java:637) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) --//

This is how I use it in Controller

//--

@Autowired(required=true)
// @Qualifier("beanValidator") private Validator validator;

 public void setValidator(Validator validator) {  
              this.validator = validator;  
          } 

--///

And this is the code in applicationcontext.xml
class="org.springmodules.validation.bean.conf.loader.annotation.AnnotationBeanValidationConfigurationLoader"/>

 <bean id="validator" class="org.springmodules.validation.bean.BeanValidator"  
      p:configurationLoader-ref="configurationLoader"/>   


 <!-- Load messages -->  
 <bean id="messageSource"  
     class="org.springframework.context.support.ResourceBundleMessageSource"  
     p:basenames="errors"/> 

--//

Applicationcontext.xml is loaded fine. I get the error when I hit submit.

//---

@RequestMapping(method=RequestMethod.POST) public ModelAndView onSubmit(@ModelAttribute("car")Car car,BindingResult bindingResult,HttpSession session) throws ServletException {

 if(bindingResult == null)
          logger.info("bindingResult is null");
      if(car == null)
          logger.info("Car is null");

      if(validator == null)
          logger.info("validator is null");
      validator.validate(car, bindingResult); 

--//

"validator is null" is printed out..

I am using Springmodules 0.9. Thanks for your quick help Willie and guys.

By Aseem on Oct 15, 2009 at 1:08 PM PDT

This is great stuff indeed (your answers to the comments aswell). Saved me hours of trial-and-error.

By Gisbert Amm on Dec 2, 2009 at 2:09 PM PST

hi

I faced some problem while executing this project and i solved those issues.
1.I used this in jdk1.6 its giving some error so i search in google and got some solution

    i.e if we use
      commons-lang.jar for jdk1.5
      commons-lang-2.3.jar for jdk1.6   problem is solved.

    2. In form.jsp page i used as it is you provided in this article but when i press submit its showing error? i solve this in the following way

    in form .jsp you have given like this < form:form commandName="userMessage">

    but when a user press submit where it should go you did not specify path

    I added < form:form commandName="userMessage" action="./form" method="post">

    problem is solved.

      But this artical is exellent ... Thanks
By raj on Dec 6, 2009 at 9:41 AM PST

Hi:

I needed someone's help!!! I cannot get the example to work. I created a project in eclipse called "contact" on Tomcat6. I deployed the application and start Tomcat. No error. When I type the url http://localhost:8080/contact/form.jsp it triggered the following error: EVERE: Neither BindingResult nor plain target object for bean name 'userMessage' available as request attribute java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'userMessage' available as request attribute at org.springframework.web.servlet.support.BindStatus. (BindStatus.java:141) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:172) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:192) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:158) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:145) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:136) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:120) at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:379) at org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:139) at Any hint or help will be greatly appreciated it.

Thanks.

Yours,

Frustrated.

By John Smith on Jan 2, 2010 at 12:01 AM PST

Hi:

It seems like the following code in the form.jsp

Your name:

Is giving me the following error: SEVERE: Neither BindingResult nor plain target object for bean name 'userMessage' available as request attribute java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'userMessage' available as request attribute at org.springframework.web.servlet.support.BindStatus. (BindStatus.java:141) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:172)

Does anybody know why or if someone could the example to work can they please send me the code to :jadeite100@yahoo.com

Any hint or help would be greatly appreciated it. Thank You

Yours,

Frustrated.

By John Smith on Jan 2, 2010 at 12:11 AM PST

In answer to your question - "It may be that there's a standard, predefined interceptor to apply BeanValidator (as opposed to injecting the Validator into the controller), but if there is, I haven't seen it. I'd be interested to hear if you, gentle reader, know of one."

You can replace your post method signature with this:

public String post(@Valid @ModelAttribute("userMessage") UserMessage userMsg, BindingResult result)

You can then remove your validator property.

By Aidan McGinley on Jan 19, 2010 at 2:39 AM PST

@Aiden: Yep, this is new with Spring 3. Though note that you will need to use Hibernate Validator, not the Bean Validation Framework (i.e., the subject of this article), which is for all intents and purposes dead. For info about Hibernate Validator please see my article on Hibernate Validator.

By Willie Wheeler on Jan 19, 2010 at 7:54 PM PST

Hey, that was interesting, The web.xml is really helpful, Thanks for writing, most people don't bother.

By Web Development Surrey on Jan 20, 2010 at 3:01 AM PST

Nice Article. Thanks. Could you also post an example on @cascadevalidation with nested beans

By Veer on Jan 20, 2010 at 7:38 AM PST

Its a very nice article. I am new to this, and I am trying to put validation in my code using the example you have posted. However, the validate method in the controller is not throwing any errors. Could you know what I could be missing?

By PC on Jan 24, 2010 at 2:19 AM PST

Very useful thanks a lot for this great article.

By redsonic on Feb 10, 2010 at 2:53 PM PST

HI,

A very nice tutorial. I tried to get your code working and faced problems which i see from above comments that fews other also had. Finally i am to a stage that my code compiles and runs fine, but i am not getting any error messages even if i leave the fields blank and say submit.

Can you please help me in finding a solution to this. I am feeling i have missed some link, but not knowing what exactly that could be.

I am in middle of a project and need to get this done ASAP.

You response is highly appreciated.

Thankyou in advance.

-- Kranthi.

By Kranthi on Feb 22, 2010 at 2:16 PM PST

I downloaded the source code from the tutorial website you mentioned, and configurationLoader is already one of the beans defined in their config xml. When I get home and look at the code I wrote, I can update this posting.

Internet Craps lernen

By Internet Craps lernen on Feb 23, 2010 at 9:58 PM PST

Hi man very helpful post but I have one problem when I specify the error messages this way : AppointmentFormBean.fullName[not.blank] = Please enter your name.

on the form I saw message containing this : 'not.blank' or more specially : not.blank which is kind of strange right ? have any idea ?

P.S. I am using spring 3 and the latest version for validation implementation.

By JOKe on Mar 2, 2010 at 7:54 AM PST

I think the intended way to inject the validator is in the @InitBinder annotated method as follows:

@Controller
public class FooController {

@Autowired
private Validator validator;

@InitBinder
public void initBinder(WebDataBinder binder) {
  binder.setRequiredFields(...)
  binder.setAllowedFields(...)
  binder.setValidator(this.validator)
}

... 

Spring-Reference/Validation

By Michael on Mar 5, 2010 at 3:05 AM PST

Post a comment

Your name:
Your e-mail address (won't be displayed):
Your web site (optional):
example: www.xyz.com
Your comment:
Preview:
By You
Please help us reduce comment spam:
Spring in Practice
My brother and I are writing Spring in Practice for Manning!

What's New?

2009-08-30 - Check out my two-part series on DZone: Spring Integration: A Hands-On Tutorial.
2009-03-25 - My new article Getting Started with Spring Batch 2.0 is available on DZone.
Home | Consulting | Tech Articles | Mailing List | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.