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.
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With