Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring - Validation with @Valid is never called

Trying to simply validate a field of my bean and instead of doing it manually wanted to check out Spring Validation, but didn't have much luck as of now.

In short:

Validation with @Valid annotation seems to never be called when I call a method of my @RestController

My code:

pom.xml (for the validation part)

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>

Spring is version 4.1.1

Validator

package mypackage;

import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

public class UtenteValidator implements Validator{

    public UtenteValidator() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return UtenteLite.class.equals(clazz);
    }

//validation test
    @Override
    public void validate(Object target, Errors errors) {
        UtenteLite user = (UtenteLite) target;

          if(user.getName != "foo") {
              errors.rejectValue("name", "name not correct");
          }

    }




}

Controller

package myPackage;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/users")
public class UsersController {


    public UsersController() {

    }

//tried to put @InitBinder, but no luck
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new UtenteValidator());
    }

    @ResponseBody
    @RequestMapping(value="", method=RequestMethod.PUT)
    public <T> ResponseEntity<T> aggiornaUtente(@RequestBody @Valid UtenteLite utente, BindingResult result)
    {
        ResponseEntity<T> responseEntity=null;

        return responseEntity;
    }


}

Te BindingResult result object shows always zero errors and the validate, supports or initBinder methods are never called.

Found this tutorial that reads:

When @InitBinder methods get called?

The @InitBinder annotated methods will get called on each HTTP request if we don't specify the 'value' element of this annotation.

WebDataBinder argument is specific to a model attribute. That means each time a model attribute is created by Spring this method will get called with a new instance of WebDataBinder.

So I tried to change my controller method to this adding a @ModelAttribute and NOW the validation code gets called BUT the requestBody object (the "utente" object) is empty, so validation always fails because the fields are all nulls:

@ResponseBody
    @RequestMapping(value="", method=RequestMethod.PUT)
    public <T> ResponseEntity<T> aggiornaUtente(@RequestBody @Valid @ModelAttribute("utente") UtenteLite utente, BindingResult result)
    { 
...
}

The utente method parameter is passed with a JSON as the body of the request.

like image 453
frankieta Avatar asked Sep 14 '25 06:09

frankieta


1 Answers

Ok,

after several tries I succeded in producing a working solution just by adding the hibernate-validation artifact reference in my pom.xml.

I wrongly supposed the hibernate-validator was mandatory only if I was usig validation annotations on the beans properties (like @NotNull, @Pattern, etc..)

So only by adding this snippet I was able to solve my problem (hope this will spare a few hours of work to someone else):

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.3.Final</version>
</dependency>

The complete code now is:

Validator

package mypackage;

import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

public class UtenteValidator implements Validator{

    public UtenteValidator() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return UtenteLite.class.equals(clazz);
    }

//validation test
    @Override
    public void validate(Object target, Errors errors) {
        UtenteLite user = (UtenteLite) target;

          if(user.getName != "foo") {
              errors.rejectValue("name", "name not correct");
          }

    }




}

Controller

package myPackage;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/users")
public class UsersController {


    public UsersController() {

    }

//tried to put @InitBinder, but no luck
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new UtenteValidator());
    }

    @ResponseBody
    @RequestMapping(value="", method=RequestMethod.PUT)
    public <T> ResponseEntity<T> aggiornaUtente(@RequestBody @Valid UtenteLite utente)
    {
        ResponseEntity<T> responseEntity=null;

        return responseEntity;
    }


}
like image 115
frankieta Avatar answered Sep 16 '25 23:09

frankieta