From 4612559446c43ed2bb32e4b69865409323da9444 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 17 Apr 2014 16:24:10 +0200 Subject: [PATCH] Automated tests against Hibernate ORM 4.3 and Hibernate Validator 5 Issue: SPR-11704 --- build.gradle | 15 +- .../LocalValidatorFactoryBean.java | 4 +- .../MessageSourceResourceBundleLocator.java | 4 +- .../MethodValidationInterceptor.java | 18 +- .../MethodValidationPostProcessor.java | 6 +- .../BeanValidationPostProcessorTests.java | 4 +- .../beanvalidation/MethodValidationTests.java | 5 +- .../beanvalidation/ValidatorFactoryTests.java | 30 +- .../BeanValidationPostProcessorTests.java | 161 ++++++++ .../MethodValidationTests.java | 113 ++++++ .../ValidatorFactoryTests.java | 366 ++++++++++++++++++ 11 files changed, 687 insertions(+), 39 deletions(-) create mode 100644 spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/BeanValidationPostProcessorTests.java create mode 100644 spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java create mode 100644 spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/ValidatorFactoryTests.java diff --git a/build.gradle b/build.gradle index 3b4680b6b02..22b0b937d8c 100644 --- a/build.gradle +++ b/build.gradle @@ -16,8 +16,9 @@ configure(allprojects) { project -> ext.aspectjVersion = "1.7.4" ext.groovyVersion = "1.8.9" ext.hibernate3Version = "3.6.10.Final" - ext.hibernate4Version = "4.2.12.Final" - ext.hibValVersion = "4.3.1.Final" + ext.hibernate4Version = "4.3.5.Final" + ext.hibVal4Version = "4.3.1.Final" + ext.hibVal5Version = "5.1.0.Final" ext.hsqldbVersion = "2.3.2" ext.jackson2Version = "2.3.2" ext.jasperReportsVersion = "5.5.1" @@ -367,7 +368,7 @@ project("spring-context") { optional("javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0") optional("org.eclipse.persistence:javax.persistence:2.0.0") optional("javax.validation:validation-api:1.0.0.GA") - optional("org.hibernate:hibernate-validator:${hibValVersion}") + optional("org.hibernate:hibernate-validator:${hibVal4Version}") optional("joda-time:joda-time:${jodaVersion}") optional("org.aspectj:aspectjweaver:${aspectjVersion}") optional("org.codehaus.groovy:groovy-all:${groovyVersion}") @@ -679,6 +680,10 @@ project("spring-orm-hibernate4") { optional("org.hibernate:hibernate-entitymanager:${hibernate4Version}") optional("javax.servlet:javax.servlet-api:3.0.1") optional("aopalliance:aopalliance:1.0") + testCompile("javax.validation:validation-api:1.1.0.GA") + testCompile("org.hibernate:hibernate-validator:${hibVal5Version}") + testCompile("javax.el:javax.el-api:2.2.4") + testCompile("org.glassfish.web:javax.el:2.2.4") } } @@ -744,7 +749,7 @@ project("spring-webmvc") { exclude group: "javax.servlet", module: "javax.servlet" } testCompile("javax.validation:validation-api:1.0.0.GA") - testCompile("org.hibernate:hibernate-validator:${hibValVersion}") + testCompile("org.hibernate:hibernate-validator:${hibVal4Version}") testCompile("org.apache.httpcomponents:httpclient:4.3.3") testCompile("commons-fileupload:commons-fileupload:1.3.1") testCompile("commons-io:commons-io:1.3") @@ -844,7 +849,7 @@ project("spring-test") { exclude group: 'org.hibernate.javax.persistence', module: 'hibernate-jpa-2.0-api' } testCompile("org.hibernate:hibernate-entitymanager:${hibernate3Version}") - testCompile("org.hibernate:hibernate-validator:${hibValVersion}") + testCompile("org.hibernate:hibernate-validator:${hibVal4Version}") testCompile("com.thoughtworks.xstream:xstream:${xstreamVersion}") testCompile("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}") testCompile("rome:rome:1.0") diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java index b6063f77039..86d0026c4e7 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,7 +64,7 @@ import org.springframework.util.ReflectionUtils; * into any target dependency of type {@link org.springframework.validation.Validator}! * *

As of Spring 4.0, this class supports Bean Validation 1.0 and 1.1, with special support - * for Hibernate Validator 4.3 and 5.0 (see {@link #setValidationMessageSource}). + * for Hibernate Validator 4.3 and 5.x (see {@link #setValidationMessageSource}). * *

Note that Bean Validation 1.1's {@code #forExecutables} method isn't supported: We do not * expect that method to be called by application code; consider {@link MethodValidationInterceptor} diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java index e14ac594fab..a610c34662a 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import org.springframework.context.support.MessageSourceResourceBundle; import org.springframework.util.Assert; /** - * Implementation of Hibernate Validator 4.3/5.0's {@link ResourceBundleLocator} interface, + * Implementation of Hibernate Validator 4.3/5.x's {@link ResourceBundleLocator} interface, * exposing a Spring {@link MessageSource} as localized {@link MessageSourceResourceBundle}. * * @author Juergen Hoeller diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java index 319095a16d0..a9ce695e8e8 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package org.springframework.validation.beanvalidation; import java.lang.reflect.Method; import java.util.Set; - import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.Validation; @@ -28,6 +27,7 @@ import javax.validation.ValidatorFactory; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.hibernate.validator.HibernateValidator; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.ReflectionUtils; import org.springframework.validation.annotation.Validated; @@ -47,8 +47,8 @@ import org.springframework.validation.annotation.Validated; * of that class. By default, JSR-303 will validate against its default group only. * *

As of Spring 4.0, this functionality requires either a Bean Validation 1.1 provider - * (such as Hibernate Validator 5.0) or the Bean Validation 1.0 API with Hibernate Validator - * 4.2 or 4.3. The actual provider will be autodetected and automatically adapted. + * (such as Hibernate Validator 5.x) or the Bean Validation 1.0 API with Hibernate Validator + * 4.3. The actual provider will be autodetected and automatically adapted. * * @author Juergen Hoeller * @since 3.1 @@ -147,7 +147,7 @@ public class MethodValidationInterceptor implements MethodInterceptor { /** - * Inner class to avoid a hard-coded Hibernate Validator 4.2/4.3 dependency. + * Inner class to avoid a hard-coded Hibernate Validator 4.3 dependency. */ private static class HibernateValidatorDelegate { @@ -159,9 +159,11 @@ public class MethodValidationInterceptor implements MethodInterceptor { public static Object invokeWithinValidation(MethodInvocation invocation, Validator validator, Class[] groups) throws Throwable { - org.hibernate.validator.method.MethodValidator methodValidator = validator.unwrap(org.hibernate.validator.method.MethodValidator.class); - Set> result = methodValidator.validateAllParameters( - invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups); + org.hibernate.validator.method.MethodValidator methodValidator = + validator.unwrap(org.hibernate.validator.method.MethodValidator.class); + Set> result = + methodValidator.validateAllParameters( + invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups); if (!result.isEmpty()) { throw new org.hibernate.validator.method.MethodConstraintViolationException(result); } diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java index f016ca1d9aa..0e93aa0141f 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,8 +49,8 @@ import org.springframework.validation.annotation.Validated; * as well. By default, JSR-303 will validate against its default group only. * *

As of Spring 4.0, this functionality requires either a Bean Validation 1.1 provider - * (such as Hibernate Validator 5.0) or the Bean Validation 1.0 API with Hibernate Validator - * 4.2 or 4.3. The actual provider will be autodetected and automatically adapted. + * (such as Hibernate Validator 5.x) or the Bean Validation 1.0 API with Hibernate Validator + * 4.3. The actual provider will be autodetected and automatically adapted. * * @author Juergen Hoeller * @since 3.1 diff --git a/spring-context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java b/spring-context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java index 6d831328c18..1e58e8f0f12 100644 --- a/spring-context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,8 @@ import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor; import org.springframework.context.support.GenericApplicationContext; /** + * Tested against Hibernate Validator 4.3, as of Spring 4.0. + * * @author Juergen Hoeller * @since 3.0 */ diff --git a/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java b/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java index 83b650c6aa8..2bb7ed6375c 100644 --- a/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java +++ b/spring-context/src/test/java/org/springframework/validation/beanvalidation/MethodValidationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,8 @@ import org.springframework.validation.annotation.Validated; import static org.junit.Assert.*; /** + * Tested against Hibernate Validator 4.3, as of Spring 4.0. + * * @author Juergen Hoeller * @since 3.1 */ @@ -103,7 +105,6 @@ public class MethodValidationTests { @Validated({MyGroup.class, Default.class}) @Retention(RetentionPolicy.RUNTIME) public @interface MyStereotype { - } } diff --git a/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java b/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java index be4f45213a0..33e291325dd 100644 --- a/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java +++ b/spring-context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,8 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; /** + * Tested against Hibernate Validator 4.3, as of Spring 4.0. + * * @author Juergen Hoeller * @since 3.0 */ @@ -67,6 +69,7 @@ public class ValidatorFactoryTests { fail("Invalid constraint violation with path '" + path + "'"); } } + validator.destroy(); } @Test @@ -86,6 +89,7 @@ public class ValidatorFactoryTests { fail("Invalid constraint violation with path '" + path + "'"); } } + validator.destroy(); } @Test @@ -133,7 +137,6 @@ public class ValidatorFactoryTests { assertTrue(errorCodes.contains("NotNull.name")); assertTrue(errorCodes.contains("NotNull.java.lang.String")); assertTrue(errorCodes.contains("NotNull")); - System.out.println(fieldError.getDefaultMessage()); fieldError = result.getFieldError("address.street"); assertEquals("address.street", fieldError.getField()); errorCodes = Arrays.asList(fieldError.getCodes()); @@ -143,7 +146,6 @@ public class ValidatorFactoryTests { assertTrue(errorCodes.contains("NotNull.street")); assertTrue(errorCodes.contains("NotNull.java.lang.String")); assertTrue(errorCodes.contains("NotNull")); - System.out.println(fieldError.getDefaultMessage()); } @Test @@ -161,7 +163,6 @@ public class ValidatorFactoryTests { assertEquals(2, errorCodes.size()); assertTrue(errorCodes.contains("NameAddressValid.person")); assertTrue(errorCodes.contains("NameAddressValid")); - System.out.println(globalError.getDefaultMessage()); } @Test @@ -175,16 +176,10 @@ public class ValidatorFactoryTests { assertEquals(3, result.getErrorCount()); FieldError fieldError = result.getFieldError("name"); assertEquals("name", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); fieldError = result.getFieldError("address.street"); assertEquals("address.street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); fieldError = result.getFieldError("addressList[0].street"); assertEquals("addressList[0].street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); } @Test @@ -198,16 +193,10 @@ public class ValidatorFactoryTests { assertEquals(3, result.getErrorCount()); FieldError fieldError = result.getFieldError("name"); assertEquals("name", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); fieldError = result.getFieldError("address.street"); assertEquals("address.street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); fieldError = result.getFieldError("addressSet[].street"); assertEquals("addressSet[].street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); } @Test @@ -271,6 +260,7 @@ public class ValidatorFactoryTests { } } + public static class ValidAddress { @NotNull @@ -285,6 +275,7 @@ public class ValidatorFactoryTests { } } + @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = NameAddressValidator.class) @@ -297,6 +288,7 @@ public class ValidatorFactoryTests { Class[] payload() default {}; } + public static class NameAddressValidator implements ConstraintValidator { @Override @@ -325,6 +317,7 @@ public class ValidatorFactoryTests { } } + public static class InnerBean { private String value; @@ -337,15 +330,20 @@ public class ValidatorFactoryTests { } } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Constraint(validatedBy=InnerValidator.class) public static @interface InnerValid { + String message() default "NOT VALID"; + Class[] groups() default { }; + Class[] payload() default {}; } + public static class InnerValidator implements ConstraintValidator { @Override diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/BeanValidationPostProcessorTests.java b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/BeanValidationPostProcessorTests.java new file mode 100644 index 00000000000..ae5008f7346 --- /dev/null +++ b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/BeanValidationPostProcessorTests.java @@ -0,0 +1,161 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.hibernatevalidator5; + +import javax.annotation.PostConstruct; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.junit.Test; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.tests.sample.beans.TestBean; +import org.springframework.validation.beanvalidation.BeanValidationPostProcessor; + +import static org.junit.Assert.*; + +/** + * Copy of {@link org.springframework.validation.beanvalidation.BeanValidationPostProcessor}, + * here to be tested against Hibernate Validator 5. + * + * @author Juergen Hoeller + * @since 4.1 + */ +public class BeanValidationPostProcessorTests { + + @Test + public void testNotNullConstraint() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); + ac.registerBeanDefinition("bean", new RootBeanDefinition(NotNullConstrainedBean.class)); + try { + ac.refresh(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getRootCause().getMessage().contains("testBean")); + assertTrue(ex.getRootCause().getMessage().contains("invalid")); + } + } + + @Test + public void testNotNullConstraintSatisfied() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); + bd.getPropertyValues().add("testBean", new TestBean()); + ac.registerBeanDefinition("bean", bd); + ac.refresh(); + } + + @Test + public void testNotNullConstraintAfterInitialization() { + GenericApplicationContext ac = new GenericApplicationContext(); + RootBeanDefinition bvpp = new RootBeanDefinition(BeanValidationPostProcessor.class); + bvpp.getPropertyValues().add("afterInitialization", true); + ac.registerBeanDefinition("bvpp", bvpp); + ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); + ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class)); + ac.refresh(); + } + + @Test + public void testSizeConstraint() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); + bd.getPropertyValues().add("testBean", new TestBean()); + bd.getPropertyValues().add("stringValue", "s"); + ac.registerBeanDefinition("bean", bd); + try { + ac.refresh(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getRootCause().getMessage().contains("stringValue")); + assertTrue(ex.getRootCause().getMessage().contains("invalid")); + } + } + + @Test + public void testSizeConstraintSatisfied() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); + bd.getPropertyValues().add("testBean", new TestBean()); + bd.getPropertyValues().add("stringValue", "ss"); + ac.registerBeanDefinition("bean", bd); + ac.refresh(); + } + + + public static class NotNullConstrainedBean { + + @NotNull + private TestBean testBean; + + @Size(min = 2) + private String stringValue; + + public TestBean getTestBean() { + return testBean; + } + + public void setTestBean(TestBean testBean) { + this.testBean = testBean; + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + @PostConstruct + public void init() { + assertNotNull("Shouldn't be here after constraint checking", this.testBean); + } + } + + + public static class AfterInitConstraintBean { + + @NotNull + private TestBean testBean; + + public TestBean getTestBean() { + return testBean; + } + + public void setTestBean(TestBean testBean) { + this.testBean = testBean; + } + + @PostConstruct + public void init() { + this.testBean = new TestBean(); + } + } + +} diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java new file mode 100644 index 00000000000..5b8cc17084f --- /dev/null +++ b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/MethodValidationTests.java @@ -0,0 +1,113 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.hibernatevalidator5; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import javax.validation.constraints.Max; +import javax.validation.constraints.NotNull; +import javax.validation.groups.Default; + +import org.junit.Test; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.validation.annotation.Validated; +import org.springframework.validation.beanvalidation.MethodValidationInterceptor; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import static org.junit.Assert.*; + +/** + * Copy of {@link org.springframework.validation.beanvalidation.MethodValidationTests}, + * here to be tested against Hibernate Validator 5. + * + * @author Juergen Hoeller + * @since 4.1 + */ +public class MethodValidationTests { + + @Test + public void testMethodValidationInterceptor() { + MyValidBean bean = new MyValidBean(); + ProxyFactory proxyFactory = new ProxyFactory(bean); + proxyFactory.addAdvice(new MethodValidationInterceptor()); + doTestProxyValidation((MyValidInterface) proxyFactory.getProxy()); + } + + @Test + public void testMethodValidationPostProcessor() { + StaticApplicationContext ac = new StaticApplicationContext(); + ac.registerSingleton("mvpp", MethodValidationPostProcessor.class); + ac.registerSingleton("bean", MyValidBean.class); + ac.refresh(); + doTestProxyValidation(ac.getBean("bean", MyValidInterface.class)); + } + + + private void doTestProxyValidation(MyValidInterface proxy) { + assertNotNull(proxy.myValidMethod("value", 5)); + try { + assertNotNull(proxy.myValidMethod("value", 15)); + fail("Should have thrown MethodConstraintViolationException"); + } + catch (javax.validation.ValidationException ex) { + // expected + } + try { + assertNotNull(proxy.myValidMethod(null, 5)); + fail("Should have thrown MethodConstraintViolationException"); + } + catch (javax.validation.ValidationException ex) { + // expected + } + try { + assertNotNull(proxy.myValidMethod("value", 0)); + fail("Should have thrown MethodConstraintViolationException"); + } + catch (javax.validation.ValidationException ex) { + // expected + } + } + + + @MyStereotype + public static class MyValidBean implements MyValidInterface { + + @Override + public Object myValidMethod(String arg1, int arg2) { + return (arg2 == 0 ? null : "value"); + } + } + + + public interface MyValidInterface { + + @NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2); + } + + + public interface MyGroup { + } + + + @Validated({MyGroup.class, Default.class}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MyStereotype { + } + +} diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/ValidatorFactoryTests.java b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/ValidatorFactoryTests.java new file mode 100644 index 00000000000..1f9a63a4ad4 --- /dev/null +++ b/spring-orm-hibernate4/src/test/java/org/springframework/validation/hibernatevalidator5/ValidatorFactoryTests.java @@ -0,0 +1,366 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.hibernatevalidator5; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.ConstraintViolation; +import javax.validation.Payload; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.HibernateValidator; +import org.junit.Test; + +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * Copy of {@link org.springframework.validation.beanvalidation.ValidatorFactoryTests}, + * here to be tested against Hibernate Validator 5. + * + * @author Juergen Hoeller + * @since 4.1 + */ +public class ValidatorFactoryTests { + + @Test + public void testSimpleValidation() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + Set> result = validator.validate(person); + assertEquals(2, result.size()); + for (ConstraintViolation cv : result) { + String path = cv.getPropertyPath().toString(); + if ("name".equals(path) || "address.street".equals(path)) { + assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); + } + else { + fail("Invalid constraint violation with path '" + path + "'"); + } + } + validator.destroy(); + } + + @Test + public void testSimpleValidationWithCustomProvider() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.setProviderClass(HibernateValidator.class); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + Set> result = validator.validate(person); + assertEquals(2, result.size()); + for (ConstraintViolation cv : result) { + String path = cv.getPropertyPath().toString(); + if ("name".equals(path) || "address.street".equals(path)) { + assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); + } + else { + fail("Invalid constraint violation with path '" + path + "'"); + } + } + validator.destroy(); + } + + @Test + public void testSimpleValidationWithClassLevel() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.setName("Juergen"); + person.getAddress().setStreet("Juergen's Street"); + Set> result = validator.validate(person); + assertEquals(1, result.size()); + Iterator> iterator = result.iterator(); + ConstraintViolation cv = iterator.next(); + assertEquals("", cv.getPropertyPath().toString()); + assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid); + } + + @Test + public void testSpringValidationFieldType() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.setName("Phil"); + person.getAddress().setStreet("Phil's Street"); + BeanPropertyBindingResult errors = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, errors); + assertEquals(1, errors.getErrorCount()); + assertThat("Field/Value type mismatch", errors.getFieldError("address").getRejectedValue(), + instanceOf(ValidAddress.class)); + } + + @Test + public void testSpringValidation() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(2, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + List errorCodes = Arrays.asList(fieldError.getCodes()); + assertEquals(4, errorCodes.size()); + assertTrue(errorCodes.contains("NotNull.person.name")); + assertTrue(errorCodes.contains("NotNull.name")); + assertTrue(errorCodes.contains("NotNull.java.lang.String")); + assertTrue(errorCodes.contains("NotNull")); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + errorCodes = Arrays.asList(fieldError.getCodes()); + assertEquals(5, errorCodes.size()); + assertTrue(errorCodes.contains("NotNull.person.address.street")); + assertTrue(errorCodes.contains("NotNull.address.street")); + assertTrue(errorCodes.contains("NotNull.street")); + assertTrue(errorCodes.contains("NotNull.java.lang.String")); + assertTrue(errorCodes.contains("NotNull")); + } + + @Test + public void testSpringValidationWithClassLevel() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.setName("Juergen"); + person.getAddress().setStreet("Juergen's Street"); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(1, result.getErrorCount()); + ObjectError globalError = result.getGlobalError(); + List errorCodes = Arrays.asList(globalError.getCodes()); + assertEquals(2, errorCodes.size()); + assertTrue(errorCodes.contains("NameAddressValid.person")); + assertTrue(errorCodes.contains("NameAddressValid")); + } + + @Test + public void testSpringValidationWithErrorInListElement() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.getAddressList().add(new ValidAddress()); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(3, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + fieldError = result.getFieldError("addressList[0].street"); + assertEquals("addressList[0].street", fieldError.getField()); + } + + @Test + public void testSpringValidationWithErrorInSetElement() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.getAddressSet().add(new ValidAddress()); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(3, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + fieldError = result.getFieldError("addressSet[].street"); + assertEquals("addressSet[].street", fieldError.getField()); + } + + @Test + public void testInnerBeanValidation() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + + MainBean mainBean = new MainBean(); + Errors errors = new BeanPropertyBindingResult(mainBean, "mainBean"); + validator.validate(mainBean, errors); + Object rejected = errors.getFieldValue("inner.value"); + assertNull(rejected); + } + + + @NameAddressValid + public static class ValidPerson { + + @NotNull + private String name; + + @Valid + private ValidAddress address = new ValidAddress(); + + @Valid + private List addressList = new LinkedList(); + + @Valid + private Set addressSet = new LinkedHashSet(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ValidAddress getAddress() { + return address; + } + + public void setAddress(ValidAddress address) { + this.address = address; + } + + public List getAddressList() { + return addressList; + } + + public void setAddressList(List addressList) { + this.addressList = addressList; + } + + public Set getAddressSet() { + return addressSet; + } + + public void setAddressSet(Set addressSet) { + this.addressSet = addressSet; + } + } + + + public static class ValidAddress { + + @NotNull + private String street; + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + } + + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @Constraint(validatedBy = NameAddressValidator.class) + public @interface NameAddressValid { + + String message() default "Street must not contain name"; + + Class[] groups() default {}; + + Class[] payload() default {}; + } + + + public static class NameAddressValidator implements ConstraintValidator { + + @Override + public void initialize(NameAddressValid constraintAnnotation) { + } + + @Override + public boolean isValid(ValidPerson value, ConstraintValidatorContext context) { + boolean valid = (value.name == null || !value.address.street.contains(value.name)); + if (!valid && "Phil".equals(value.name)) { + context.buildConstraintViolationWithTemplate( + context.getDefaultConstraintMessageTemplate()).addNode("address").addConstraintViolation().disableDefaultConstraintViolation(); + } + return valid; + } + } + + + public static class MainBean { + + @InnerValid + private InnerBean inner = new InnerBean(); + + public InnerBean getInner() { + return inner; + } + } + + + public static class InnerBean { + + private String value; + + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + } + + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @Constraint(validatedBy=InnerValidator.class) + public static @interface InnerValid { + + String message() default "NOT VALID"; + + Class[] groups() default { }; + + Class[] payload() default {}; + } + + + public static class InnerValidator implements ConstraintValidator { + + @Override + public void initialize(InnerValid constraintAnnotation) { + } + + @Override + public boolean isValid(InnerBean bean, ConstraintValidatorContext context) { + context.disableDefaultConstraintViolation(); + if (bean.getValue() == null) { + context.buildConstraintViolationWithTemplate("NULL"). addNode("value").addConstraintViolation(); + return false; + } + return true; + } + } + +}