Dear Spring community,
What I am trying to implement is the following:
- I would like to have a custom validator per controller (via
@InitBinder) - I would like Spring to call
validator.validate()(so not this way) - I would like to use JSR-303
@Validannotation for that - The bean to be validated (
RegistrationForm) does not have any per-field JSR-303 annotations - I don’t want to include validation implementation (like Hibernate) into classpath; it will be useless as from above statement
I basically follow the steps mentioned here:
- I add
javax.validation.validation-api:validation-apias my dependency - I use
<mvc:annotation-driven /> - I mark my model with
@Valid:
public String onRegistrationFormSubmitted(@ModelAttribute("registrationForm") @Valid RegistrationForm registrationForm, BindingResult result) ...
So what happens, is that validation API tries to locate any implementation and fails:
Caused by: javax.validation.ValidationException: Unable to find a default provider
at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:264)
at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:183)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
The way out is to define a validator property for AnnotationDrivenBeanDefinitionParser:
<bean name="validator" class="org.company.module.RegistrationFormValidator" />
<mvc:annotation-driven validator="validator" />
but this approach means that the validator will be set to all controllers by ConfigurableWebBindingInitializer.initBinder().
I understand that I am trying to use the framework in a special way, but what the community will say, if there is a special meaning for validator property which tells that validator does not need to be resolved, e.g.
<mvc:annotation-driven validator="manual" />
with special treatment:
--- AnnotationDrivenBeanDefinitionParser.java.orig 2011-06-30 14:33:10.287577300 +0200
+++ AnnotationDrivenBeanDefinitionParser.java 2011-06-30 14:34:27.897449000 +0200
@@ -152,6 +152,10 @@
private RuntimeBeanReference getValidator(Element element, Object source, ParserContext parserContext) {
if (element.hasAttribute("validator")) {
+ if ("manual".equals(element.getAttribute("validator"))) {
+ return null;
+ }
+
return new RuntimeBeanReference(element.getAttribute("validator"));
}
else if (jsr303Present) {
Any feedback is welcomed.
P.S. Repost from Spring Forum.
This is also a repost of my answer/workaround on the above mentioned forum. Anyway I think it might help having it here as well.
The only workaround I found was to implement my own
@Validannotation, once Spring (at least in 3.1.1.RELEASE code base) only checks the method argument annotation’s simple name (please look into theorg.springframework.web.method.annotation.ModelAttributeMethodProcessorclass below). This way, I don’t need to addjavax.validation.validation-api:validation-apito my project’s dependencies and I stop getting the infamousjavax.validation.ValidationException: Unable to find a default provider.