Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syntactically incorrect request sent upon submitting form with invalid data in Spring MVC (which uses hibernate Validator)

Login form:

<f:form class="form-horizontal" method="post" action="/login"
    commandName="logindata">
    <fieldset>
        <legend class="text-info">Login</legend>
        <div class="control-group">
            <f:label path="uname" class="control-label" for="uname">Username</f:label>
            <div class="controls">
                <f:input type="text" path="uname" name="uname" id="uname"
                    placeholder="Username" />
            </div>
        </div>
        <div class="control-group">
            <f:label path="pwd" class="control-label" for="pwd">Password</f:label>
            <div class="controls">
                <f:input type="password" path="pwd" name="pwd" id="pwd"
                    placeholder="Password" />
            </div>
        </div>
        <div class="control-group">
            <div class="controls">
                <button type="submit" class="btn" id="login">
                    Login <i class="icon-chevron-right"></i>
                </button>
            </div>
        </div>
        <div id="errormsg" class="alert alert-error">${message}</div>
    </fieldset>
</f:form>

the loginData class:

package com.demo.forms;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

public class loginData {
    @Length(min=4)
    private String uname; 

    @NotEmpty
    private String pwd;

    public String getUname() {
        return uname;
    }
    public void setUname(String uname) {
        this.uname = uname;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

Controller methods for showing and submitting the form: (Shows homepage which contains signup form and login form)

@RequestMapping(value = "/", method=RequestMethod.GET)
    public String showHome(Model model)
    {
        loginservice.logout();
        model.addAttribute("logindata", new loginData());
        model.addAttribute("signupdata", new signupData());
        return "home";
    }

Method called upon submitting login form:

@RequestMapping(value = "login", method=RequestMethod.POST)
    public String submitloginForm(@Valid loginData logindata, SessionStatus state, Model model, BindingResult result)
    {
            if((loginservice.loggedin()) || (result.hasErrors()))
            {
                return showHome(model);
            }
            else
            {
                String uname = logindata.getUname();
                String pwd = logindata.getPwd();
                if(loginservice.login(uname, pwd))
                {
                    model.addAttribute("user",uname);
                    return "redirect:profile";
                }
                else
                {
                    model.addAttribute("message","Invalid Username/Password");
                    return showHome(model);
                }   
            }   
    }


The login works fine when the data entered is 'valid' (either correct or wrong). However, when it is invalid, for instance, when the password field is empty or the username is less than four characters long, following error is shown:

The request sent by the client was syntactically incorrect.

Any idea how this might be fixed?

like image 377
Sagar Aiya Avatar asked Mar 11 '13 10:03

Sagar Aiya


1 Answers

You have to modify the order of your arguments. Put the BindingResult result parameter always directly after the parameter with the @Valid annotation.

@RequestMapping(value = "login", method=RequestMethod.POST)
public String submitloginForm(@Valid loginData logindata, BindingResult result,
                              SessionStatus state, Model model)

This was even mentioned in this weeks This Week in Spring - March 5th, 2013 blog entry

Someone asked me this the other day and I felt like it was worthy of a mention: in your Spring MVC @Controller class handler methods, make sure that the BindingResult argument is immediately after the model or command argument, like this: @RequestMapping(...) public String handleRequest( @ModelAttribute @Valid YourCustomPojo attempt, BindingResult result). In this example, handleRequest will validate the POJO (YourCustomPojo) - checking the POJO for JSR303-annotations and attempting to apply the constraints because the POJO is annotated with @Valid - and stash any errors in the BindingResult, which it makes available if we ask for it.

Spring will

  • 0) determin the handler method
  • 1) create an instance of loginData
  • 2) populate it
  • 3) validate it, and store the validation result in BindingResult
  • 4) invoke the method (with loginData and BindingResult values), no matter whenever the binding Result contains an error or not
like image 75
Ralph Avatar answered Nov 14 '22 16:11

Ralph