Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my Spring 3 Validator Validating Everything on the Model?

I have a spring 3 controller with a validator for one of the methods. It insists on validating every object on the model. Would anyone be able to explain to me why it does this or if I'm doing something wrong?

According to the docs, 5.7.4.3 Configuring a JSR-303 Validator for use by Spring MVC (http://static.springsource.org/spring/docs/3.0.0.RC3/spring-framework-reference/html/ch05s07.html)

With JSR-303, a single javax.validation.Validator instance typically validates all model objects that declare validation constraints. To configure a JSR-303-backed Validator with Spring MVC, simply add a JSR-303 Provider, such as Hibernate Validator, to your classpath. Spring MVC will detect it and automatically enable JSR-303 support across all Controllers.

Example:

@Controller public class WhaleController {          @Autowired         private Validator myValidator;          @Autowired         private WhaleService whaleService;          @InitBinder         protected void initBinder(WebDataBinder binder) {                 binder.setValidator(this.myValidator);         }          @RequestMapping(value="/save-the-whales")         @Transactional         public void saveTheWhales(@Valid WhaleFormData formData, BindingResult errors, Model model) {                 if (!errors.hasFieldErrors()) {                         Whale whale = new Whale();                          whale.setBreed( formData.getBreed() );                          this.whaleService.saveWhale( whale );                          model.addAttribute("whale", whale);                  }                 model.addAttribute("errors", errors.getFieldErrors());         }  } 

When run it will complain that Whale is an invalid target for myValidator (which is set to validate WhaleFormData, and does so fine). Whale is a POJO with no validation constraints, annotation and no config anywhere. Through trial and error I've found that ANY object placed on the model will attempt to be validated and fail if the validator is not setup to handle it. Primitives are just fine.

Can anyone tell me why this is, point me to the appropriate documentation and/or tell me the best way to put something on the model without having it validated?

In the case above I would like to place "whale" on the model as it will now have a unique whaleId() that it received from my persistence layer.

Thanks!

like image 538
Josh Johnson Avatar asked Jan 17 '11 17:01

Josh Johnson


People also ask

What does @validated do?

The @Validated annotation is a class-level annotation that we can use to tell Spring to validate parameters that are passed into a method of the annotated class.

What is the use of @valid Annotation in Spring?

The @Valid annotation will tell spring to go and validate the data passed into the controller by checking to see that the integer numberBetweenOneAndTen is between 1 and 10 inclusive because of those min and max annotations.


1 Answers

I guess this behaviour is not covered in the documentation well.

The problem is caused by the following:

  1. By default, @InitBinder-annotated method is called for each non-primitive model attribute, both incoming and outcoming (the purpose of calling it for outcoming attibutes is to allow you to register custom PropertyEditors, which are used by form tags when rendering a form).

  2. DataBinder.setValidator() contains a defensive check that call Validator.supports() and throws an exception if false is returned. So, there is no attempt to perform a validation, just an early check.

The solution is to restrict the scope of @InitBinder to particular attribute:

@InitBinder("whaleFormData") protected void initBinder(WebDataBinder binder) { ... } 
like image 112
axtavt Avatar answered Sep 25 '22 17:09

axtavt