MemeStorm

Exploring the Spring Framework and Application Development

Spring Binding and Validation: Introduction

Posted in All by Jon on the February 20th, 2006

You want to slurp in some data, perhaps from a simple form or from
request parameters. To do this, we’ll explore the AbstractCommandController and learn about the related issues of binding and validation. Spring makes this kind of thing pretty effortless, and this will serve as the foundation of exploring more advanced form-handling.

How to do it

The controllers we wrote about in previous blog entries, such as the MultiActionController, are generally used for carrying out actions. What if you wanted to rather input some data first, perhaps through request parameters? Well one way to do this is the hard way:

String val = (String) request.getParameter("someParamName");

Those were the days. Untyped, inflexible, error-prone, with all sorts of casting (imagine if I wanted a date or an integer).

A much better approach use data binding - let Spring bind the incoming data to a Plain Old JavaBean (POJO) for you - then you can simply use that POJO as you’d expect. Spring calls these beans commands, which I think is a bit of a misnomer, but there you go. Let’s see this in action. First, we’re going to modify our dispatch-servlet.xml configuration file to include a new controller:

<bean id="commandController"
  class="com.memestorm.web.CommandController">
</bean>

Now let’s modify our handler mappings (see previous blog entries if you need to understand these) to include a mapping to our command controller:

/cmd=commandController
/*=dispatchController

So in theory now, something like http://localhost:8080/send/cmd?age=10 will get sent to our command controller. Now the command controller we’ll use is the simplest around. It extends the AbstractCommandController. Here’s the code:

public class CommandController extends AbstractCommandController {

  public CommandController() {
    setCommandClass(SimpleCommand.class);
  }

  protected ModelAndView handle(HttpServletRequest request,
		HttpServletResponse response, Object command,
                BindException errors) throws Exception {

    SimpleCommand cmd = (SimpleCommand) command;

    PrintWriter pw = response.getWriter();
    pw.println(cmd);
    return null;
  }
}

The first thing you’ll notice (probably because I have it in bold) is that the constructor calls setCommandClass() with the class that will hold the incoming values. This is the command class I spoke about earlier. All incoming parameters are mapped onto this class, automatically, for you. We pass the setCommandClass() the class so that it can instantiate a new instance every time the controller is invoked. Now take a look at the handle() method, somewhat more complicated than the others that we’ve seen in Basic Spring Web MVC Example. The two extra parameters are the command (which Spring will have created and populated for you), and an object listing errors (which we’ll describe later).

The method is pretty simple: It casts the command object to the expected type, and then writes it to the response. Let’s look at the command object:

public class SimpleCommand {
 Integer age;
 String name;

 public String getName() {return name;}

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

 public Integer getAge() {return age;}

 public void setAge(Integer age) {this.age = age;}

 public String toString() {
   return "Name=[" + this.name + "], Age=[" + this.age + "]";
 }
}

You must admit, that’s pretty straightforward. A typed container, just ready to be populated by incoming values. Now, if you invoke something like http://localhost:8080/skeleton3/send/cmd?name=Jon&age=30 you’ll see the output as Name=[Jon], Age=[30]. This is pretty darn nice for a number of reasons:

  • Notice that I didn’t write any code to bind the incoming parameters to the command bean. It’s automatic.
  • Notice that the command bean is typed - getAge() returns an Integer and somehow Spring converted the incoming field to the appropriate type automatically.

This is a considerable step up from getRequestParameter(). It even works for a form input. For example, here is a simple form that you can use to invoke our controller:

<form action="send/cmd" method="post">
 Name: <input type="text" name="name" />
 Age: <input type="text" name="age" />
</form>

But wait, there’s more! If we extend our handler() method to dump some information found in the errors parameter, we’ll see further magic:

pw.println("<hr>" + "Error count=" + errors.getErrorCount());
pw.println("<br>Errors for age field"  + errors.getFieldErrors("age"));
pw.println("<br>Input value for age field: " + errors.getFieldValue("age"));
pw.println("<br>" + errors.getGlobalErrors());

Now if we invoke it with an error in the age value (for example, some letters instead of digits) as in: http://localhost:8080/skeleton3/send/cmd?name=Jon&age=crikey we’ll see the following output:

Name=[Jon], Age=[null]
<hr>Error count=1
<br>Errors for age field[Field error in object 'command' on field 'age': rejected value [crikey]; codes [typeMismatch.command.age,typeMismatch.age,typeMismatch.java.lang.Integer,typeMismatch]; arguments [MessageSourceResolvable: codes [command.age,age]; arguments []; default message [age]]; default message [Failed to convert property value of type [java.lang.String] to required type [java.lang.Integer] for property 'age'; nested exception is java.lang.NumberFormatException: For input string: "crikey"]]
<br>Input value for age field: crikey

Now notice that the age value is null (it can’t convert ‘crikey’), notice that we have an error count, that we have access to the original text that the user entered, and we have a good error message too. That’s a lot of magic for very little effort.

But wait, there’s even more. With a simple change to the constructor, we can validate input values too. Here is an example modification:

public CommandController() {
  setCommandClass(SimpleCommand.class);
  setValidator(new Validator(){
    public boolean supports(Class clazz) {
      return (clazz.equals(SimpleCommand.class));
    }
    public void validate(Object command, Errors errors) {
      SimpleCommand incoming = (SimpleCommand) command;
      ValidationUtils.rejectIfEmpty(errors, “age”, “required.age”);
      if (incoming.getAge() != null && incoming.getAge() > 30)
        errors.reject(”over.the.hill”, “too old”);
   }});
}

As you can see, we’ve set a validator. A validator simply implements the Validator interface—here we’ve done it with a simple anonymous class. You can instead write full classes for the validators and wire them in with the web context instead - in that way you can promote some reuse with your validators too. The validator interface has two methods. supports() tells the system what kind of class it validates. The validate method performs the actual validation. We make use of ValidationUtils to ensure that the age is not empty. You can, instead, write your own validation as we do checking that the age is not too high. So now, if we pass in an age of 34 say, we’ll get the following output:

...
[Error in object 'command': codes [over.the.hill.command,over.the.hill]; arguments []; default message [too old]]

There is in fact a little more magic too (message interpretation) but that will have to wait for another day.


Print This Post Print This Post

15 Responses to 'Spring Binding and Validation: Introduction'

Subscribe to comments with RSS or TrackBack to 'Spring Binding and Validation: Introduction'.


  1. on April 3rd, 2006 at 2:03 pm

    […] This blog entry describes how simple it is to bind request data to POJOs in Spring MVC. […]

  2. RichBaldwin said,

    on July 12th, 2006 at 11:26 am

    This is great stuff. I thought it desirable to return the user to the orginating form when fields failed to validate. I’m fairly certain that setting up a multiactioncontroller would give me the functionality, but this might be a bit messy and there might be a better approach.


  3. on December 5th, 2006 at 3:29 pm

    Nicely written blog. keeps to the point and very clear. . better clarity than Spring’s documentation. You should think about going into publishing a book - half the books out there on java technologies are not up to snuff.

    Cheers

    Shankar

  4. tech said,

    on December 6th, 2006 at 3:49 am

    Ha, thanks Shankar. I’ve already written one!

  5. Brandon said,

    on December 28th, 2006 at 8:11 am

    Great blog, helps me gather arsenal to convinece my chief software engineer they are currently doing it all wrong (The current app returns all input values as a param mapping and they manual construct the POJO the page represents using request.getParameter(…) ).

    I have two questions (if you could just email me directly):
    (1) Where can I get a reciepe on setting up SPRING binding? I have experience with Struts on my previous 2 applications (personal apps), and alittle bit of SPRING DAOs.

    (2) I need to build an arsenal to convience my boss that it is okay to put some POJOs to session (making sure to remove them when the application is done with them of course). Currently everything is being put to request, so when everytime a form is submitted the application has to go back to the DB and “re-inflate” the object the page represented. This is really bad because if the page has labels the represent properties of the object they are lost when the form is submitted (not added to the param mapping).

    Any advice would be great THANKS!

  6. Arman Sharif said,

    on June 26th, 2007 at 9:23 am

    I’m currently working on a form validation library, so it’s interesting to see how different frameworks approach this. What I’d really like is something that allows you to do validation with hardly any code and no xml/mapping files. If you’re interested, check out http://www.jreform.org

  7. Swetha said,

    on August 2nd, 2007 at 2:58 pm

    My controller is not identifying setCommandClass function. Is it pre-defined or we have to write the functionality. Any help is really appreciated

  8. Antonio Sánchez said,

    on October 15th, 2007 at 2:46 am

    Ok. That was quite interesting, but how we can bind information in case we were using a MultiActionController????
    Thanks!

  9. Andre said,

    on December 25th, 2007 at 12:52 am

    swetha, your controller need to extend AbstractCommandController in order to get the setCommandClass function

  10. Waquin said,

    on February 14th, 2008 at 5:03 pm

    You said that message interpretation would have to wait untill another day. When is that day? It would be really handy!

  11. Ashokkumar said,

    on February 28th, 2008 at 6:28 am

    I want to interpret the error message please give me the link for the interpretation ASAP.

  12. lalitha said,

    on March 3rd, 2008 at 11:09 pm

    Thanks it is working fine up to the given block

    please tell how to interpret the error message in to jsp page using upstract command controller

  13. skiN said,

    on March 12th, 2008 at 9:21 am

    Thanks a lot……..
    i was struggling like anything… but your example helped a lot…
    Thanks once again.

  14. Dhrubo said,

    on March 17th, 2008 at 7:21 am

    Hi Jon,
    Dhrubo here. I think you put it right command bean is a complete misnomer. If these page controllers were called command beans there was no problem. But these command beans should be called form beans. Struts got it right.
    What do you think.
    Cheers… dhrubo

  15. Pete said,

    on April 9th, 2008 at 12:19 am

    Not sure why you need any of this, if you use a MultiActionController you may specify a command object as a 3rd parameter

    e.g.

    public ModelAndView handleViewList(HttpServletRequest request,
    HttpServletResponse response, SearchCommand searchCommand) throws Exception {

    where SearchCommand is the command object - any request parameters that match its properties will be bound automatically. Bean must have a default constructor.

    In Spring 2.5 it a little more flexible e.g.

    @RequestMapping(”/myurl.html”)
    public ModelAndView addMultiple(@ModelAttribute(”command”) SearchCommand command,
    HttpServletRequest request, HttpServletResponse response)

Leave a Reply