Wednesday, April 24, 2013

Spring MVC bind exception in the form validation

A few minutes ago I found an intricate problem when using Spring MVC. Let's jump directly to the code:



HomeWebController.java
....



@RequestMapping(method = RequestMethod.POST)
public String login( @Valid LoginRequest login, HttpServletRequest request,
HttpServletResponse response
, BindingResult result 
) {
  request.setAttribute("home", login);
   logger.info("binding result=" + result);
  if (result.hasErrors()) {
   return "home";
  }

...
return "feedbacklist";


}

....
home.jsp
....

<form:form commandName="home" action="home" class="form" data-ajax="false" method="post">
  <form:errors path="*" cssClass="errorblock" element="div" />
    <form:input path="username"  placeholder="Please enter your email" data-role="none" class="field topCurve" autocorrect="off" autocapitalize="off"  type="email" pattern="[^ @]*@[^ @]*" />
        <form:password path="pwd" placeholder="Please enter your password" data-role="none"  class="field btnCurve" autocorrect="off" autocapitalize="off" />
       
        <form:button  class="button rounded" id="submithome" data-role="none" type="submit">Submit</form:button>
        
    </form:form>


After a few hours searching in the web,  I found the answer.
There are 2 small thing are incorrect in the code above:
1. BindingResult parameter must be placed immediately after validated bean.

public String login( @Valid LoginRequest login, BindingResult result, HttpServletRequest request,
HttpServletResponse response 
)


This is one of the Spring  weakness. Spring is very rigid in  the naming and parameter.
If we didn't follow this, the following exception will occur:


org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors




2. Naming in the jsp "<form:form commandName= ..." and controller must according to the Bean Class.
Let say our java bean class is: "LoginRequest", then we MUST name commandName attributes as "loginRequest".
following is the correction:

home.jsp
<form:form commandName="loginRequest" action="home" class="form" data-ajax="false" method="post">




HomeWebController.java
@RequestMapping(method = RequestMethod.POST)
    public String login( @Valid  LoginRequest login, BindingResult result, HttpServletRequest request,
HttpServletResponse response) {
request.setAttribute("loginRequest", login);
logger.info("binding result=" + result);
if (result.hasErrors()) {
return "home";
}


...

return "/feedbacklist";
    }



Intricate huh?