Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does BindingResult have to follow @Valid?

I was struggling to get my Spring MVC validation to return to the page submitted page when I had errors. I finally solved the problem by noticing that BindingResult needs to be next to form parameter I'm validating.

For example if I amend the checkPersonInfo method in the spring.io tutorial(http://spring.io/guides/gs/validating-form-input/) to -

@RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@Valid Person person, BindingResult bindingResult, Model model) {
    if (bindingResult.hasErrors()) {
        return "form";
    }
    return "redirect:/results";
}

Then it will work and redirect to the form page, but if I change it to -

@RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@Valid Person person, Model model, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "form";
    }
    return "redirect:/results";
}

Then it redirects to /errors

What is the cause of this?

like image 338
farrellmr Avatar asked Mar 05 '15 21:03

farrellmr


3 Answers

The BindingResult has to follow the object that is bound. The reason is that if you have more objects that are bound you must know which BindingResult belongs to which object.

like image 121
Henry Avatar answered Oct 26 '22 13:10

Henry


Yeah, Today I took a long time to check why cannot back to the submitted page but goes to a default whitelable error page.

After debugging got the source code

// org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
    throw new BindException(binder.getBindingResult());
}

if BindingResult does not follow @Valid , causes isBindExceptionRequired(binder, parameter) return true and then directly throw exception so cannot execute code in controller method.

// org.springframework.web.method.annotation.ModelAttributeMethodProcessor#isBindExceptionRequired 
protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) {
    int i = methodParam.getParameterIndex();
    Class<?>[] paramTypes = methodParam.getMethod().getParameterTypes();
    boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
    return !hasBindingResult;
}  
like image 28
zhuguowei Avatar answered Oct 26 '22 15:10

zhuguowei


You can potentially have multiple model attributes in your request handler, each with their own binding result. To accomodate this, Spring decided to bind binding result parameters to the previous paramater.

like image 4
Sotirios Delimanolis Avatar answered Oct 26 '22 13:10

Sotirios Delimanolis