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

Validation Messages

Code listing: /WEB-INF/classes/errors.properties
UserMessage.name[not.blank]=Please enter your name.
UserMessage.name[length]=Please enter no more than {2} characters.
UserMessage.email[not.blank]=Please enter your e-mail address.
UserMessage.email[email]=Please enter a valid e-mail address.
UserMessage.email[length]=Please enter no more than {2} characters.
UserMessage.text[not.blank]=Please enter a message.
UserMessage.text[length]=Please enter no more than {2} characters.

The keys should be fairly self-explanatory given UserMessage above. Each key involves a class, a field and an annotation. The values are parametrizable messages, not unlike Commons Validator messages if you're familiar with those. In the three length messages, I'm using {2} to indicate argument #2—viz., max—for the length validation rule. Argument #1 happens to be min, and argument #0 in general appears to be the form bean itself. I can imagine that it would be nice to be able to use the form bean to get at the specific submitted value so you could say things like "You entered 4012 characters, but the limit is 4000 characters." And I think there's actually a way to do that though I don't myself know how to do it yet. (This is another one of those areas where I'd appreciate whatever information you may have.)

I mentioned above that I chose @NotBlank instead of @Length(min = 1, max = 80). The reason is that I wanted to use a specific error message ("Please enter your name") if the message is blank. I could have just used "Please enter a name between 1-80 characters" but that sounds slightly silly compared to "Please enter your name", and since I'm a usability guy I care about such things.

The JSPs

We have two JSPs: the form itself, and a basic (really basic) "thank you" page.

Code listing: /WEB-INF/form.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Contact Us</title>
        <style>
            .form-item { margin: 20px 0; }
            .form-label { font-weight: bold; }
            .form-error-field { background-color: #FFC; }
            .form-error-message { font-weight: bold; color: #900; }
        </style>
    </head>
    <body>
    
<h1>Contact Us</h1>

<%-- Give command object a meaningful name instead of using default name, 'command' --%>
<form:form commandName="userMessage">
    <div class="form-item">
        <div class="form-label">Your name:</div>
        <form:input path="name" size="40" cssErrorClass="form-error-field"/>
        <div class="form-error-message"><form:errors path="name"/></div>
    </div>
    <div class="form-item">
        <div class="form-label">Your e-mail address:</div>
        <form:input path="email" size="40" cssErrorClass="form-error-field"/>
        <div class="form-error-message"><form:errors path="email"/></div>
    </div>
    <div class="form-item">
        <div class="form-label">Your message:</div>
        <form:textarea path="text" rows="12" cols="60" cssErrorClass="form-error-field"/>
        <div class="form-error-message"><form:errors path="text"/></div>
    </div>
    <div class="form-item">
        <input type="submit" value="Submit" />
    </div>
</form:form>

    </body>
</html>

This is just a standard Spring WebMVC form, so I'll invoke my "I assume you know Spring WebMVC" assumption here. The cssErrorClass attribute is kind of fun if you don't already know about it. It indicates the CSS class to use in the event of a validation error. You can combine that with the cssClass attribute (which applies in the non-error case) though I haven't done that here.

Now here's the basic "thank you" page:

Code listing: /WEB-INF/thanks.jsp
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Thank You</title>
    </head>
    <body>
        <h1>Thank You</h1>
    </body>
</html>

(I told you it was basic...)

OK, now we're ready to move onto application configuration. Almost done!

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

Comments (51)

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

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

Hi,

I have been using spring validation module until I updated my project from spring2.5 to Spring 3 and I was so disappointed to see that I can't any more use it because of its dependency to spring 2.5 which broke everything.

Now, I'm migrating to hibernate validator (jsr 303) which seems to be the best today.

:)

By redsonic on Mar 13, 2010 at 8:39 AM PST

Hello. Thanks for your post.

But i have an error with it:

Error creating bean with name 'exportController': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.validation.Validator com.scartel.starlab.resourceservice.web.controllers.exportresources.ExportController.validator; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.validation.Validator] is defined: Unsatisfied dependency of type [interface org.springframework.validation.Validator]: expected at least 1 matching bean

It cant autowire validator.

Controller: http://pastebin.com/vDkZezBt

Form: http://pastebin.com/qDMdwVA9

Dispatcher: http://pastebin.com/GUj3qz8c

Can you help me. What i did wrong?

By Chupa on Apr 1, 2010 at 1:29 AM PDT

It was very helpful Thanx a lot.

By rranja on Apr 1, 2010 at 5:33 AM PDT

thanks!!

By stan on Apr 4, 2010 at 9:44 AM PDT

Please note at line number 35. It returns form for any validation failure, but if the form contains any reference data like country list as combobox which come from database, then the combobox shows empty. What is the solution ?

By limon on Apr 16, 2010 at 8:30 AM PDT

Hi

 I have  implemented spring validation  successfully  but how can i pass local class to messages. 

i am not able to get messages from different different message properties files hope here i will get solution

Thanks

By Vishal on Jun 1, 2010 at 7:48 AM PDT

How to integrate SWF 2.0 and validation framework (declarative validation)? any sample applications/link ?

By Murali on Jun 2, 2010 at 12:16 AM PDT

Hi,

Can we use the above method to validate the following:

  1. if the class object attribute is a string or numeric value.
  2. if there are any scripting tags in the attributes.

Please help!! :(

Regards, Jitish

By jitishnair on Jun 2, 2010 at 5:49 AM PDT

Hi,

Can we apply multilanguage function to Error message:

I am getting all message from message properties file but when i am trying to use different language message properties file it is not taking because i am not finding any parameter for applying local class.

Regards, Vishal

By vishal on Jun 2, 2010 at 7:20 AM PDT

spring-modules stopped getting work done on it a few years ago. A group has forked and continued development, see github here:

http://github.com/astubbs/spring-modules

By Toolman on Jun 30, 2010 at 3:39 AM PDT

Nice define for the intermediate developer.

By Web Content Writing on Sep 28, 2010 at 5:16 AM PDT

Thanks a lot.Its Very helpful.....

By Kuni Biswal on Sep 29, 2010 at 5:32 AM PDT

Post a comment

Comments currently suppressed due to excessive spam. I'll reinstate them later, this time with approvals turned on. :-)

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.