Page 1 of 2 12 LastLast
Results 1 to 10 of 20

Thread: Commons-Validator to Spring MVC 3 Validation

  1. #1

    Default Commons-Validator to Spring MVC 3 Validation

    Hi all,

    I'm migrating my web app from Spring 2.5.6 to Spring 3.0.2 and thought I would also use the latest JSR-303 validation.

    I used to validate my (form) beans in 3 steps. Step 2 and 3 are optional depending on the data being validated:

    1: My Validator (which implements org.springframework.validation.Validator) would invoke a Commons-Validator backed validator:

    Code:
    <!-- Commons-Validator backed bean validator. -->
    <bean id="beanValidator" class="org.springmodules.validation.commons.DefaultBeanValidator">
    	<property name="validatorFactory">
    		<ref local="validatorFactory" />
    	</property>
    </bean>
    Code:
    @Autowired
    private Validator beanValidator;
    
    @Override
    public void validate(final Object command, final Errors errors) {
    	// Invoke the Commons-Validator backed validator
    	beanValidator.validate(command, errors);
    }
    I had configured the appropriate validations with a validation.xml.

    2. Any custom validation that did NOT require access to the request object was done in the validate method:

    Code:
    @Override
    public void validate(final Object command, final Errors errors) {
    
    	final CreateAccountForm form = (CreateAccountForm) command;
    
    	// Invoke the Commons-Validator backed validator
    	beanValidator.validate(command, errors);
    
    	if (!errors.hasFieldErrors("password1")
    		&& !errors.hasFieldErrors("password2")) {
    		// Only report possible password conflicts when there are no other
    		// errors with either password1 or password2
    		if (!form.getPassword1().equals(form.getPassword2())) {
    			errors
    					.reject(
    								"formErrors.passwordMismatch",
    								"The supplied passwords did not match. Please make sure both passwords are typed exactly the same.");
    			errors
    					.rejectValue("password1",
    								"formErrors.password1Mismatch",
    								"This password must be exactly the same as the second password.");
    			errors
    					.rejectValue("password2",
    								"formErrors.password2Mismatch",
    								"This password must be exactly the same as the first password.");
    		}
    	}
    
    }
    3. Any custom validation that did require access to the request object was done in the controller's onBindAndValidate method.

    How can each of the above steps be achieved with Spring MVC 3? So far I understand 1 can be achieved easily by annotating the backing form's properties with @NotEmpty. @Email etc. and then use the @Valid annotation in my handling method:

    Code:
    @RequestMapping(value = "/createAccount", method = RequestMethod.POST)
    public String handleCreateAccount(final HttpServletRequest request,
    		@Valid final CreateAccountForm form, final Model model) {
    But where can I perform my custom validation? If I use a custom validator as per below will 1 still happen?

    Code:
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
    	binder.setValidator(new CreateAccountValidator());
    }
    Also with the above will a custom binding initializer as exampled in Pet Clinic still have effect?

    Code:
    <!--
    	- This bean processes annotated handler methods, applying PetClinic-specific PropertyEditors
    	- for request parameter binding. It overrides the default AnnotationMethodHandlerAdapter.
    -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    	<property name="webBindingInitializer">
    		<bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer"/>
    	</property>
    </bean>
    Many thanks for any input,
    Nes

  2. #2

    Default

    Not sure if it is the cleanest way to do things, but got things going as follows:

    1: My Validator (which still implements org.springframework.validation.Validator) would invoke a JSR-303 validator:

    Code:
    <!-- Use the LocalValidatorFactoryBean to configure a default JSR-303 Validator as a Spring bean:  -->
    <bean id="beanValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
    Code:
    @Autowired
    private Validator beanValidator;
    
    @Override
    public void validate(final Object target, final Errors errors) {
    
    	// Invoke the JSR-303 Validator to validate field values
    	beanValidator.validate(target, errors);
    2. Any custom validation is done in the validate method of my custom validator (in this case a CreateAccountValidator):

    Code:
    @Override
    public void validate(final Object target, final Errors errors) {
    
    	// Invoke the JSR-303 Validator to validate field values
    	beanValidator.validate(target, errors);
    		
    	final CreateAccountForm form = (CreateAccountForm) target;
    
    	if (!errors.hasFieldErrors("password1")
    			&& !errors.hasFieldErrors("password2")) {
    		// Only report possible password conflicts when there are no other
    		// errors with either password1 or password2
    		if (!form.getPassword1().equals(form.getPassword2())) {
    			errors
    				.reject(
    					"formErrors.passwordMismatch",
    					"The supplied passwords did not match. Please make sure both passwords are typed exactly the same.");
    			errors
    				.rejectValue("password1",
    					"formErrors.password1Mismatch",
    				        "This password must be exactly the same as the second password.");
    			errors
    				.rejectValue("password2",
    					"formErrors.password2Mismatch",
    					"This password must be exactly the same as the first password.");
    		}
    	}
    I inject my custom validator as follows:

    Code:
    @Autowired
    @Qualifier("createAccountValidator")
    Validator validator;
    
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
    	binder.setValidator(validator);
    }
    I inject a bean here instead of "new CreateAccountValidator()" as the validation bean is injected with dependencies for business logic required for the validation.

    Turned out I could live without the request object for validation.

    Nes

  3. #3

    Exclamation Inormation required

    Hello friends,

    I am using Spring 3.0. I am trying to use JSR303 vallidator as well as custom validator.

    Now for the example stated above can you please provide me the names of Jar files that you have on your CLASSPATH?

  4. #4

    Default

    It's actually deceptively simple to enable the JSR-303 validation. Hava a look at: http://static.springsource.org/sprin...beanvalidation, especially the section labeled 'Spring MVC 3 validation'

    In terms of enabling it, all you need to do is add
    <mvc:annotation-driven />
    to your controller bean file. Of course it can get more exotic, which is where all the other confusing discussion comes from in that section. Bottom line, it's a 4 step process
    1. Add <mvc:annotation-driven /> to your controller bean file
    2. Add libraries (either explicitly or via maven or ivy, etc) for the following libraries (hibernate-validator and javax.validation.validation-api)
    3. Add @Valid to controller method parameters where you want validation preformed on submit
    4. Add validation annotations (ex @Max, @NotNull) to your properties of that class that will be validated


    To do a custom validation, you can write your own validation annotation. Again.. pretty easy once you get the hang of it. For that, I'd recommend having a look at the hibernate validator reference doc at: http://docs.jboss.org/hibernate/stab...nstraints.html

  5. #5
    Join Date
    Jun 2010
    Posts
    13

    Default

    @nesyarug,
    Can you post your classpath?
    I tried to use commons validator with Spring MVC 3 but I run into classpath issues, see my post at http://forum.springsource.org/showthread.php?t=93695

    I tried to use org.springmodules.validation.commons.DefaultBeanVa lidator to no avail

    Also I am posting my beanValidator below
    <bean id="validatorFactory"
    class="org.springmodules.validation.commons.Defaul tValidatorFactory">
    <property name="validationConfigLocations">
    <list>
    <value>/WEB-INF/conf/struts/validation.xml</value>
    <value>/WEB-INF/conf/struts/validator-rules.xml</value>
    </list>
    </property>
    </bean>

    <bean id="beanValidator"
    class="org.springmodules.validation.commons.Defaul tBeanValidator">
    <property name="validatorFactory" ref="validatorFactory"/>
    </bean>
    Last edited by blumm; Aug 16th, 2010 at 11:07 AM. Reason: Added detail

  6. #6
    Join Date
    Aug 2010
    Posts
    24

    Default

    Quote Originally Posted by msecrist View Post
    It's actually deceptively simple to enable the JSR-303 validation. Hava a look at: http://static.springsource.org/sprin...beanvalidation, especially the section labeled 'Spring MVC 3 validation'

    In terms of enabling it, all you need to do is add
    <mvc:annotation-driven />
    to your controller bean file. Of course it can get more exotic, which is where all the other confusing discussion comes from in that section. Bottom line, it's a 4 step process
    1. Add <mvc:annotation-driven /> to your controller bean file
    2. Add libraries (either explicitly or via maven or ivy, etc) for the following libraries (hibernate-validator and javax.validation.validation-api)
    3. Add @Valid to controller method parameters where you want validation preformed on submit
    4. Add validation annotations (ex @Max, @NotNull) to your properties of that class that will be validated
    I read the reference guide and pretty much followed the steps that are written above...however I am getting this error:

    Code:
    2010-08-16 13:45:01,449 DEBUG [org.springframework.web.servlet.DispatcherServlet] - <Could not complete request>
    org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.AbstractMethodError: org.hibernate.ejb.HibernatePersistence.getProviderUtil()Ljavax/persistence/spi/ProviderUtil;
            at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:823)
            at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
            at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
            at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
            at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:861)
            at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
            at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1584)
            at java.lang.Thread.run(Thread.java:619)
    Caused by: java.lang.AbstractMethodError: org.hibernate.ejb.HibernatePersistence.getProviderUtil()Ljavax/persistence/spi/ProviderUtil;
            at javax.persistence.Persistence$PersistenceUtilImpl.isLoaded(Persistence.java:110)
            at org.hibernate.validator.engine.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:33)
            at org.hibernate.validator.engine.resolver.DefaultTraversableResolver.isReachable(DefaultTraversableResolver.java:112)
            at org.hibernate.validator.engine.resolver.SingleThreadCachedTraversableResolver.isReachable(SingleThreadCachedTraversableResolver.java:47)
            at org.hibernate.validator.engine.ValidatorImpl.isValidationRequired(ValidatorImpl.java:764)
            at org.hibernate.validator.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:331)
            at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForRedefinedDefaultGroup(ValidatorImpl.java:278)
            at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:260)
            at org.hibernate.validator.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:213)
            at org.hibernate.validator.engine.ValidatorImpl.validate(ValidatorImpl.java:119)
            at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:75)
            at org.springframework.validation.DataBinder.validate(DataBinder.java:692)
            at com.krfs.web.ClientTypeController.initBinder(ClientTypeController.java:159)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.initBinder(HandlerMethodInvoker.java:392)
            at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveModelAttribute(HandlerMethodInvoker.java:764)
            at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:355)
            at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:170)
            at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421)
            at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:409)
            at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:774)
            ... 21 more
    any idea what the problem could be?

    Thanks

  7. #7

    Default

    Are you using Hibernate for persistence? What version(s) of the hibernate Jars are you using?

  8. #8
    Join Date
    Aug 2010
    Posts
    24

    Default

    From the POM:
    Code:
                <artifactId>com.springsource.org.hibernate</artifactId>
                <version>3.3.2.GA</version>
    
                <artifactId>com.springsource.org.hibernate.ejb</artifactId>
                <version>3.4.0.GA</version>
    
                <artifactId>com.springsource.javax.persistence</artifactId>
                <version>2.0.0</version>
    and we were using Hibernate-validation 4.0.2.GA

  9. #9

    Default

    I don't think this is a validator issue. The Hibernate validator doesn't depend on the hibernate persistence modules. I've got the following in my pom.xml file.
    Code:
    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-validator</artifactId>
       <version>4.0.2.GA</version>
    </dependency>
    This pulled in validation-api-1.0.0.GA.jar as a dependency. I use hibernate JPA in several of my projects and the only difference I see is the specification for the javax.persistence module. I let Maven resolve that dependency from the hibernate-entitymanager dependency and I get ejb3-persistence-1.0.2. The only two dependencies I explicitly specify are as follows.
    Code:
    <dependency>
    	<groupId>org.hibernate</groupId>
    	<artifactId>hibernate-core</artifactId>
    	<version>3.3.2.GA</version>
    </dependency>
    <dependency>
    	<groupId>org.hibernate</groupId>
    	<artifactId>hibernate-entitymanager</artifactId>
    	<version>3.4.0.GA</version>
    </dependency>

  10. #10
    Join Date
    Aug 2010
    Posts
    24

    Default

    hmm this is weird, just to give it a shot i explicitly added those dependencies to my pom file and got a different error:

    Code:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myService': Injection of persistence dependencies
    failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/spring/applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: myPersistenceUnit] Unable to build EntityManagerFactory
            at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:341)
    So is the issue a conflict of dependencies?

    Thanks!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •