Photo by emdot - http://www.flickr.com/photos/emdot/97177377/
del.icio.us Digg DZone Reddit StumbleUpon
1 | 2 | 3 | Next »
Software Development

Annotation-Based Validation with the Spring Bean Validation Framework

Use Java annotations to validate your Spring WebMVC form beans.

The Spring Bean Validation Framework, which is part of the Spring Modules project, allows you to perform validation declaratively using Java annotations. I've always liked the declarative approach, which we saw for instance in Commons Validator, but annotation-based validation is (as far as I know) unique to the Bean Validation Framework. There is however JSR 303 (Bean Validation), which appears to have the same goals.

While it very well could be subpar Googling skills on my part, there doesn't seem to be much detailed how-to information out there on actually using the Bean Validation Framework. Hence this article.

I'm using Spring 2.5.x (specifically, Spring 2.5.5) and Spring Modules 0.9. I assume that you already know Spring and Spring WebMVC in particular.

If you want to download the code, you can do so here:

You'll have to download the dependencies separately though.

Dependencies

Here's what you'll need (again, I'm using Spring 2.5.x and Spring Modules 0.9):

  • commons-collections.jar
  • commons-lang.jar
  • commons-logging.jar
  • spring.jar
  • spring-modules-validation.jar
  • spring-webmvc.jar

Java Sources

I'm going to do things a little differently than I normally do, and start with the Java first. We're going to build a very simple "Contact Us" form of the sort that you might use to ask a question, complain about lousy service, or whatever. Since we're just showing how validation works, I've left out the service and persistence tiers. We're going to do everything with a form bean and a controller.

Here's the form bean:

Code listing: contact.UserMessage
package contact;

import org.springmodules.validation.bean.conf.loader.annotation.handler.Email;
import org.springmodules.validation.bean.conf.loader.annotation.handler.Length;
import org.springmodules.validation.bean.conf.loader.annotation.handler.NotBlank;

public final class UserMessage {
    
    @NotBlank
    @Length(max = 80)
    private String name;
    
    @NotBlank
    @Email
    @Length(max = 80)
    private String email;
    
    @NotBlank
    @Length(max = 4000)
    private String text;
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

The bean itself is pretty uninteresting—I have field for the user's name, e-mail address, and the message text. But the cool part is that I've included annotations that specify validation constraints. It's probably self-explanatory, but I've specified that none of the fields is allowed to be blank, and I've also specified the maximum lengths for each. (You can also specify minimum lengths, which one could use instead of @NotBlank, but I'm using @NotBlank instead for a reason I'll explain in just a bit.) Finally, I've specified that email needs to be a valid e-mail address. It's that simple!

Here are the rest of the validation rules you can use.

Now here's the Spring MVC controller, which I've implemented as a POJO controller:

Code listing: contact.ContactController
package contact;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public final class ContactController {
    
    @Autowired
    private Validator validator;
    
    public void setValidator(Validator validator) {
        this.validator = validator;
    }
    
    @RequestMapping(value = "/form", method = RequestMethod.GET)
    public ModelMap get() {
        
        // Because we're not specifying a logical view name, the
        // DispatcherServlet's DefaultRequestToViewNameTranslator kicks in.
        return new ModelMap("userMessage", new UserMessage());
    }
    
    @RequestMapping(value = "/form", method = RequestMethod.POST)
    public String post(@ModelAttribute("userMessage") UserMessage userMsg,
            BindingResult result) {
        
        validator.validate(userMsg, result);
        if (result.hasErrors()) { return "form"; }
        
        // Use the redirect-after-post pattern to reduce double-submits.
        return "redirect:thanks";
    }
    
    @RequestMapping("/thanks")
    public void thanks() {
    }
}

The Bean Validation Framework includes its own Validator implementation, called BeanValidator, and I'm making that injectable here. Also, note that we're going to autowire it in.

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.

The noteworthy method here is the second post() method, which contains the validation code. I just call the standard validate() method, passing in the form bean and the BindingResult, and return the current logical view name if there's an error. That way the form shows the validation error messages, which we'll see below. If everything passes validation, I just redirect to a "thank you" page.

Now let's look at how we define the validation messages that the end user sees if his form submission fails validation.

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

Comments (7)

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
Post a comment
Home | Consulting | Articles | Blog | About | Contact
Copyright © 2008 Wheeler Software, LLC.