Support for Bean Validation 2.0 container elements (with BV 2.0 test setup)
Includes latest dependency updates (Hibernate Validator 6.0.1, Caffeine 2.5.4, Netty 4.1.14, Tomcat 8.5.19, Johnzon 1.1.2, JsonPath 2.4, Jython 2.7.1) Issue: SPR-15839 Issue: SPR-15808
This commit is contained in:
parent
48f95e9b96
commit
de09f8ca1f
53
build.gradle
53
build.gradle
|
@ -39,9 +39,9 @@ configure(allprojects) { project ->
|
|||
ext.activationApiVersion = "1.1.1"
|
||||
ext.annotationApiVersion = "1.3"
|
||||
ext.aspectjVersion = "1.9.0.BETA-6"
|
||||
ext.beanvalVersion = "1.1.0.Final"
|
||||
ext.beanvalVersion = "2.0.0.Final"
|
||||
ext.cacheApiVersion = "1.0.0"
|
||||
ext.caffeineVersion = "2.5.3"
|
||||
ext.caffeineVersion = "2.5.4"
|
||||
ext.eclipselinkVersion = "2.6.5-RC2"
|
||||
ext.ehcacheVersion = "2.10.4"
|
||||
ext.ehcachejcacheVersion = "1.0.1"
|
||||
|
@ -54,7 +54,7 @@ configure(allprojects) { project ->
|
|||
ext.gsonVersion = "2.8.1"
|
||||
ext.hamcrestVersion = "1.3"
|
||||
ext.hibernate5Version = "5.2.10.Final"
|
||||
ext.hibvalVersion = "5.4.1.Final"
|
||||
ext.hibvalVersion = "6.0.1.Final"
|
||||
ext.hsqldbVersion = "2.4.0"
|
||||
ext.httpasyncVersion = "4.1.3"
|
||||
ext.httpclientVersion = "4.5.3"
|
||||
|
@ -77,7 +77,7 @@ configure(allprojects) { project ->
|
|||
ext.junitJupiterVersion = '5.0.0-RC2'
|
||||
ext.junitPlatformVersion = '1.0.0-RC2'
|
||||
ext.log4jVersion = '2.8.2'
|
||||
ext.nettyVersion = "4.1.13.Final"
|
||||
ext.nettyVersion = "4.1.14.Final"
|
||||
ext.niomultipartVersion = "1.1.0"
|
||||
ext.okhttp3Version = "3.8.1"
|
||||
ext.poiVersion = "3.16"
|
||||
|
@ -94,7 +94,7 @@ configure(allprojects) { project ->
|
|||
ext.snakeyamlVersion = "1.18"
|
||||
ext.testngVersion = "6.11"
|
||||
ext.tiles3Version = "3.0.7"
|
||||
ext.tomcatVersion = "8.5.16"
|
||||
ext.tomcatVersion = "8.5.19"
|
||||
ext.tyrusVersion = "1.13.1"
|
||||
ext.undertowVersion = "1.4.18.Final"
|
||||
ext.websocketVersion = "1.1"
|
||||
|
@ -512,9 +512,8 @@ project("spring-context") {
|
|||
optional("javax.interceptor:javax.interceptor-api:${interceptorApiVersion}")
|
||||
optional("javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0")
|
||||
optional("javax.money:money-api:1.0.1")
|
||||
optional("org.eclipse.persistence:javax.persistence:${jpaVersion}")
|
||||
optional("javax.validation:validation-api:${beanvalVersion}")
|
||||
optional("org.hibernate:hibernate-validator:${hibvalVersion}")
|
||||
optional("javax.validation:validation-api:1.1.0.Final")
|
||||
optional("org.hibernate:hibernate-validator:5.4.1.Final")
|
||||
optional("joda-time:joda-time:${jodaVersion}")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
|
@ -660,6 +659,17 @@ project("spring-jdbc") {
|
|||
}
|
||||
}
|
||||
|
||||
project("spring-context-indexer") {
|
||||
description = "Spring Context Indexer"
|
||||
|
||||
dependencies {
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("javax.inject:javax.inject:1")
|
||||
testCompile("javax.annotation:javax.annotation-api:${annotationApiVersion}")
|
||||
testCompile("org.eclipse.persistence:javax.persistence:${jpaVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-context-support") {
|
||||
description = "Spring Context Support"
|
||||
|
||||
|
@ -682,22 +692,16 @@ project("spring-context-support") {
|
|||
testCompile("org.apache.poi:poi:${poiVersion}")
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
testCompile("javax.validation:validation-api:${beanvalVersion}")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibvalVersion}")
|
||||
testRuntime("javax.el:javax.el-api:${elApiVersion}")
|
||||
testRuntime("org.glassfish:javax.el:3.0.1-b08")
|
||||
testRuntime("javax.annotation:javax.annotation-api:${annotationApiVersion}")
|
||||
testRuntime("com.sun.mail:javax.mail:${javamailVersion}")
|
||||
testRuntime("org.ehcache:jcache:${ehcachejcacheVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-context-indexer") {
|
||||
description = "Spring Context Indexer"
|
||||
|
||||
dependencies {
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("javax.inject:javax.inject:1")
|
||||
testCompile("javax.annotation:javax.annotation-api:${annotationApiVersion}")
|
||||
testCompile("org.eclipse.persistence:javax.persistence:${jpaVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
|
||||
|
@ -782,7 +786,7 @@ project("spring-web") {
|
|||
testRuntime("com.sun.xml.bind:jaxb-core:${jaxbVersion}")
|
||||
testRuntime("com.sun.xml.bind:jaxb-impl:${jaxbVersion}")
|
||||
testRuntime("javax.json:javax.json-api:1.1")
|
||||
testRuntime("org.apache.johnzon:johnzon-jsonb:1.1.1")
|
||||
testRuntime("org.apache.johnzon:johnzon-jsonb:1.1.2")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -891,7 +895,7 @@ project("spring-webmvc") {
|
|||
testRuntime("org.jetbrains.kotlin:kotlin-script-util:${kotlinVersion}")
|
||||
testRuntime("org.jetbrains.kotlin:kotlin-compiler:${kotlinVersion}")
|
||||
testRuntime("org.jruby:jruby:9.1.12.0")
|
||||
testRuntime("org.python:jython-standalone:2.5.3")
|
||||
testRuntime("org.python:jython-standalone:2.7.1")
|
||||
testRuntime("org.webjars:underscorejs:1.8.3")
|
||||
testRuntime("org.glassfish:javax.el:3.0.1-b08")
|
||||
testRuntime("com.sun.xml.bind:jaxb-core:${jaxbVersion}")
|
||||
|
@ -999,7 +1003,7 @@ project("spring-webflux") {
|
|||
testRuntime("org.jetbrains.kotlin:kotlin-script-util:${kotlinVersion}")
|
||||
testRuntime("org.jetbrains.kotlin:kotlin-compiler:${kotlinVersion}")
|
||||
testRuntime("org.jruby:jruby:9.1.12.0")
|
||||
testRuntime("org.python:jython-standalone:2.5.3")
|
||||
testRuntime("org.python:jython-standalone:2.7.1")
|
||||
testRuntime("org.synchronoss.cloud:nio-multipart-parser:${niomultipartVersion}")
|
||||
testRuntime("org.webjars:underscorejs:1.8.3")
|
||||
testRuntime("org.glassfish:javax.el:3.0.1-b08")
|
||||
|
@ -1050,7 +1054,7 @@ project("spring-test") {
|
|||
exclude group: "io.netty", module: "netty"
|
||||
}
|
||||
optional("org.skyscreamer:jsonassert:${jsonassertVersion}")
|
||||
optional("com.jayway.jsonpath:json-path:2.3.0")
|
||||
optional("com.jayway.jsonpath:json-path:2.4.0")
|
||||
optional("org.reactivestreams:reactive-streams")
|
||||
optional("io.projectreactor:reactor-core")
|
||||
optional("io.projectreactor:reactor-test")
|
||||
|
@ -1139,7 +1143,6 @@ project("spring-aspects") {
|
|||
ajc("org.aspectj:aspectjtools:${aspectjVersion}")
|
||||
rt("org.aspectj:aspectjrt:${aspectjVersion}")
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
provided("org.eclipse.persistence:javax.persistence:${jpaVersion}")
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
|
@ -1269,7 +1272,7 @@ configure(rootProject) {
|
|||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = '3.5.1'
|
||||
gradleVersion = '4.1'
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.beanvalidation2;
|
||||
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
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"));
|
||||
}
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@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();
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@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();
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@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"));
|
||||
}
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@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();
|
||||
ac.close();
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.beanvalidation2;
|
||||
|
||||
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.beans.MutablePropertyValues;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
|
||||
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationInterceptor;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class MethodValidationTests {
|
||||
|
||||
@Test
|
||||
public void testMethodValidationInterceptor() {
|
||||
MyValidBean bean = new MyValidBean();
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
proxyFactory.addAdvice(new MethodValidationInterceptor());
|
||||
proxyFactory.addAdvisor(new AsyncAnnotationAdvisor());
|
||||
doTestProxyValidation((MyValidInterface) proxyFactory.getProxy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodValidationPostProcessor() {
|
||||
StaticApplicationContext ac = new StaticApplicationContext();
|
||||
ac.registerSingleton("mvpp", MethodValidationPostProcessor.class);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("beforeExistingAdvisors", false);
|
||||
ac.registerSingleton("aapp", AsyncAnnotationBeanPostProcessor.class, pvs);
|
||||
ac.registerSingleton("bean", MyValidBean.class);
|
||||
ac.refresh();
|
||||
doTestProxyValidation(ac.getBean("bean", MyValidInterface.class));
|
||||
ac.close();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void doTestProxyValidation(MyValidInterface proxy) {
|
||||
assertNotNull(proxy.myValidMethod("value", 5));
|
||||
try {
|
||||
assertNotNull(proxy.myValidMethod("value", 15));
|
||||
fail("Should have thrown ValidationException");
|
||||
}
|
||||
catch (javax.validation.ValidationException ex) {
|
||||
// expected
|
||||
}
|
||||
try {
|
||||
assertNotNull(proxy.myValidMethod(null, 5));
|
||||
fail("Should have thrown ValidationException");
|
||||
}
|
||||
catch (javax.validation.ValidationException ex) {
|
||||
// expected
|
||||
}
|
||||
try {
|
||||
assertNotNull(proxy.myValidMethod("value", 0));
|
||||
fail("Should have thrown ValidationException");
|
||||
}
|
||||
catch (javax.validation.ValidationException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
proxy.myValidAsyncMethod("value", 5);
|
||||
try {
|
||||
proxy.myValidAsyncMethod("value", 15);
|
||||
fail("Should have thrown ValidationException");
|
||||
}
|
||||
catch (javax.validation.ValidationException ex) {
|
||||
// expected
|
||||
}
|
||||
try {
|
||||
proxy.myValidAsyncMethod(null, 5);
|
||||
fail("Should have thrown ValidationException");
|
||||
}
|
||||
catch (javax.validation.ValidationException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
assertEquals("myValue", proxy.myGenericMethod("myValue"));
|
||||
try {
|
||||
proxy.myGenericMethod(null);
|
||||
fail("Should have thrown ValidationException");
|
||||
}
|
||||
catch (javax.validation.ValidationException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@MyStereotype
|
||||
public static class MyValidBean implements MyValidInterface<String> {
|
||||
|
||||
@Override
|
||||
public Object myValidMethod(String arg1, int arg2) {
|
||||
return (arg2 == 0 ? null : "value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void myValidAsyncMethod(String arg1, int arg2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String myGenericMethod(String value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface MyValidInterface<T> {
|
||||
|
||||
@NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);
|
||||
|
||||
@MyValid
|
||||
@Async void myValidAsyncMethod(@NotNull(groups = OtherGroup.class) String arg1, @Max(10) int arg2);
|
||||
|
||||
T myGenericMethod(@NotNull T value);
|
||||
}
|
||||
|
||||
|
||||
public interface MyGroup {
|
||||
}
|
||||
|
||||
|
||||
public interface OtherGroup {
|
||||
}
|
||||
|
||||
|
||||
@Validated({MyGroup.class, Default.class})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyStereotype {
|
||||
}
|
||||
|
||||
|
||||
@Validated({OtherGroup.class, Default.class})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyValid {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.beanvalidation2;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.context.support.StaticMessageSource;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Kazuki Shimizu
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class SpringValidatorAdapterTests {
|
||||
|
||||
private final Validator nativeValidator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
||||
private final SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter(nativeValidator);
|
||||
|
||||
private final StaticMessageSource messageSource = new StaticMessageSource();
|
||||
|
||||
|
||||
@Before
|
||||
public void setupSpringValidatorAdapter() {
|
||||
messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} is must be between {2} and {1}");
|
||||
messageSource.addMessage("Same", Locale.ENGLISH, "{2} must be same value with {1}");
|
||||
messageSource.addMessage("password", Locale.ENGLISH, "Password");
|
||||
messageSource.addMessage("confirmPassword", Locale.ENGLISH, "Password(Confirm)");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUnwrap() {
|
||||
Validator nativeValidator = validatorAdapter.unwrap(Validator.class);
|
||||
assertSame(this.nativeValidator, nativeValidator);
|
||||
}
|
||||
|
||||
@Test // SPR-13406
|
||||
public void testNoStringArgumentValue() {
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setPassword("pass");
|
||||
testBean.setConfirmPassword("pass");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("password"), is(1));
|
||||
assertThat(errors.getFieldValue("password"), is("pass"));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("password"), Locale.ENGLISH),
|
||||
is("Size of Password is must be between 8 and 128"));
|
||||
}
|
||||
|
||||
@Test // SPR-13406
|
||||
public void testApplyMessageSourceResolvableToStringArgumentValueWithResolvedLogicalFieldName() {
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setPassword("password");
|
||||
testBean.setConfirmPassword("PASSWORD");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("password"), is(1));
|
||||
assertThat(errors.getFieldValue("password"), is("password"));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("password"), Locale.ENGLISH),
|
||||
is("Password must be same value with Password(Confirm)"));
|
||||
}
|
||||
|
||||
@Test // SPR-13406
|
||||
public void testApplyMessageSourceResolvableToStringArgumentValueWithUnresolvedLogicalFieldName() {
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setEmail("test@example.com");
|
||||
testBean.setConfirmEmail("TEST@EXAMPLE.IO");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("email"), is(1));
|
||||
assertThat(errors.getFieldValue("email"), is("test@example.com"));
|
||||
assertThat(errors.getFieldErrorCount("confirmEmail"), is(1));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("email"), Locale.ENGLISH),
|
||||
is("email must be same value with confirmEmail"));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("confirmEmail"), Locale.ENGLISH),
|
||||
is("Email required"));
|
||||
}
|
||||
|
||||
@Test // SPR-15123
|
||||
public void testApplyMessageSourceResolvableToStringArgumentValueWithAlwaysUseMessageFormat() {
|
||||
messageSource.setAlwaysUseMessageFormat(true);
|
||||
|
||||
TestBean testBean = new TestBean();
|
||||
testBean.setEmail("test@example.com");
|
||||
testBean.setConfirmEmail("TEST@EXAMPLE.IO");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
|
||||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("email"), is(1));
|
||||
assertThat(errors.getFieldValue("email"), is("test@example.com"));
|
||||
assertThat(errors.getFieldErrorCount("confirmEmail"), is(1));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("email"), Locale.ENGLISH),
|
||||
is("email must be same value with confirmEmail"));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("confirmEmail"), Locale.ENGLISH),
|
||||
is("Email required"));
|
||||
}
|
||||
|
||||
@Test // SPR-15839
|
||||
public void testListElementConstraint() {
|
||||
BeanWithListElementConstraint bean = new BeanWithListElementConstraint();
|
||||
bean.setProperty(Arrays.asList("no", "element", "can", "be", null));
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(bean, "bean");
|
||||
validatorAdapter.validate(bean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("property[4]"), is(1));
|
||||
assertNull(errors.getFieldValue("property[4]"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Same(field = "password", comparingField = "confirmPassword")
|
||||
@Same(field = "email", comparingField = "confirmEmail")
|
||||
static class TestBean {
|
||||
|
||||
@Size(min = 8, max = 128)
|
||||
private String password;
|
||||
|
||||
private String confirmPassword;
|
||||
|
||||
private String email;
|
||||
|
||||
@Pattern(regexp = "[\\p{L} -]*", message = "Email required")
|
||||
private String confirmEmail;
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getConfirmPassword() {
|
||||
return confirmPassword;
|
||||
}
|
||||
|
||||
public void setConfirmPassword(String confirmPassword) {
|
||||
this.confirmPassword = confirmPassword;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getConfirmEmail() {
|
||||
return confirmEmail;
|
||||
}
|
||||
|
||||
public void setConfirmEmail(String confirmEmail) {
|
||||
this.confirmEmail = confirmEmail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Documented
|
||||
@Constraint(validatedBy = {SameValidator.class})
|
||||
@Target({TYPE, ANNOTATION_TYPE})
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(SameGroup.class)
|
||||
@interface Same {
|
||||
|
||||
String message() default "{org.springframework.validation.beanvalidation.Same.message}";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
String field();
|
||||
|
||||
String comparingField();
|
||||
|
||||
@Target({TYPE, ANNOTATION_TYPE})
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@interface List {
|
||||
Same[] value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Documented
|
||||
@Inherited
|
||||
@Retention(RUNTIME)
|
||||
@Target({TYPE, ANNOTATION_TYPE})
|
||||
@interface SameGroup {
|
||||
|
||||
Same[] value();
|
||||
}
|
||||
|
||||
|
||||
public static class SameValidator implements ConstraintValidator<Same, Object> {
|
||||
|
||||
private String field;
|
||||
|
||||
private String comparingField;
|
||||
|
||||
private String message;
|
||||
|
||||
public void initialize(Same constraintAnnotation) {
|
||||
field = constraintAnnotation.field();
|
||||
comparingField = constraintAnnotation.comparingField();
|
||||
message = constraintAnnotation.message();
|
||||
}
|
||||
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
BeanWrapper beanWrapper = new BeanWrapperImpl(value);
|
||||
Object fieldValue = beanWrapper.getPropertyValue(field);
|
||||
Object comparingFieldValue = beanWrapper.getPropertyValue(comparingField);
|
||||
boolean matched = ObjectUtils.nullSafeEquals(fieldValue, comparingFieldValue);
|
||||
if (matched) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
context.disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(message)
|
||||
.addPropertyNode(field)
|
||||
.addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class BeanWithListElementConstraint {
|
||||
|
||||
private List<@NotNull String> property;
|
||||
|
||||
public List<String> getProperty() {
|
||||
return property;
|
||||
}
|
||||
public void setProperty(List<String> property) {
|
||||
this.property = property;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.beanvalidation2;
|
||||
|
||||
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.Optional;
|
||||
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.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.hibernate.validator.HibernateValidatorFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.Environment;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ValidatorFactoryTests {
|
||||
|
||||
@Test
|
||||
public void testSimpleValidation() throws Exception {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||
assertEquals(2, result.size());
|
||||
for (ConstraintViolation<ValidPerson> 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 nativeValidator = validator.unwrap(Validator.class);
|
||||
assertTrue(nativeValidator.getClass().getName().startsWith("org.hibernate"));
|
||||
assertTrue(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory);
|
||||
assertTrue(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory);
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleValidationWithCustomProvider() throws Exception {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.setProviderClass(HibernateValidator.class);
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||
assertEquals(2, result.size());
|
||||
for (ConstraintViolation<ValidPerson> 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 nativeValidator = validator.unwrap(Validator.class);
|
||||
assertTrue(nativeValidator.getClass().getName().startsWith("org.hibernate"));
|
||||
assertTrue(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory);
|
||||
assertTrue(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory);
|
||||
|
||||
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<ConstraintViolation<ValidPerson>> result = validator.validate(person);
|
||||
assertEquals(1, result.size());
|
||||
Iterator<ConstraintViolation<ValidPerson>> 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<String> 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<String> errorCodes = Arrays.asList(globalError.getCodes());
|
||||
assertEquals(2, errorCodes.size());
|
||||
assertTrue(errorCodes.contains("NameAddressValid.person"));
|
||||
assertTrue(errorCodes.contains("NameAddressValid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithAutowiredValidator() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||
LocalValidatorFactoryBean.class);
|
||||
LocalValidatorFactoryBean validator = ctx.getBean(LocalValidatorFactoryBean.class);
|
||||
|
||||
ValidPerson person = new ValidPerson();
|
||||
person.expectsAutowiredValidator = true;
|
||||
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<String> errorCodes = Arrays.asList(globalError.getCodes());
|
||||
assertEquals(2, errorCodes.size());
|
||||
assertTrue(errorCodes.contains("NameAddressValid.person"));
|
||||
assertTrue(errorCodes.contains("NameAddressValid"));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationWithOptionalField() throws Exception {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
MainBeanWithOptional mainBean = new MainBeanWithOptional();
|
||||
Errors errors = new BeanPropertyBindingResult(mainBean, "mainBean");
|
||||
validator.validate(mainBean, errors);
|
||||
Object rejected = errors.getFieldValue("inner.value");
|
||||
assertNull(rejected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListValidation() throws Exception {
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
ListContainer listContainer = new ListContainer();
|
||||
listContainer.addString("A");
|
||||
listContainer.addString("X");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(listContainer, "listContainer");
|
||||
errors.initConversion(new DefaultConversionService());
|
||||
validator.validate(listContainer, errors);
|
||||
|
||||
FieldError fieldError = errors.getFieldError("list[1]");
|
||||
assertEquals("X", errors.getFieldValue("list[1]"));
|
||||
}
|
||||
|
||||
|
||||
@NameAddressValid
|
||||
public static class ValidPerson {
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@Valid
|
||||
private ValidAddress address = new ValidAddress();
|
||||
|
||||
@Valid
|
||||
private List<ValidAddress> addressList = new LinkedList<>();
|
||||
|
||||
@Valid
|
||||
private Set<ValidAddress> addressSet = new LinkedHashSet<>();
|
||||
|
||||
public boolean expectsAutowiredValidator = false;
|
||||
|
||||
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<ValidAddress> getAddressList() {
|
||||
return addressList;
|
||||
}
|
||||
|
||||
public void setAddressList(List<ValidAddress> addressList) {
|
||||
this.addressList = addressList;
|
||||
}
|
||||
|
||||
public Set<ValidAddress> getAddressSet() {
|
||||
return addressSet;
|
||||
}
|
||||
|
||||
public void setAddressSet(Set<ValidAddress> 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<NameAddressValid, ValidPerson> {
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void initialize(NameAddressValid constraintAnnotation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(ValidPerson value, ConstraintValidatorContext context) {
|
||||
if (value.expectsAutowiredValidator) {
|
||||
assertNotNull(this.environment);
|
||||
}
|
||||
boolean valid = (value.name == null || !value.address.street.contains(value.name));
|
||||
if (!valid && "Phil".equals(value.name)) {
|
||||
context.buildConstraintViolationWithTemplate(
|
||||
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class MainBean {
|
||||
|
||||
@InnerValid
|
||||
private InnerBean inner = new InnerBean();
|
||||
|
||||
public InnerBean getInner() {
|
||||
return inner;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class MainBeanWithOptional {
|
||||
|
||||
@InnerValid
|
||||
private InnerBean inner = new InnerBean();
|
||||
|
||||
public Optional<InnerBean> getInner() {
|
||||
return Optional.ofNullable(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<? extends Payload>[] payload() default {};
|
||||
}
|
||||
|
||||
|
||||
public static class InnerValidator implements ConstraintValidator<InnerValid, InnerBean> {
|
||||
|
||||
@Override
|
||||
public void initialize(InnerValid constraintAnnotation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
if (bean.getValue() == null) {
|
||||
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ListContainer {
|
||||
|
||||
@NotXList
|
||||
private List<String> list = new LinkedList<>();
|
||||
|
||||
public void addString(String value) {
|
||||
list.add(value);
|
||||
}
|
||||
|
||||
public List<String> getList() {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Constraint(validatedBy = NotXListValidator.class)
|
||||
public @interface NotXList {
|
||||
|
||||
String message() default "Should not be X";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
|
||||
|
||||
public static class NotXListValidator implements ConstraintValidator<NotXList, List<String>> {
|
||||
|
||||
@Override
|
||||
public void initialize(NotXList constraintAnnotation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(List<String> list, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if ("X".equals(list.get(i))) {
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addBeanNode().inIterable().atIndex(i).addConstraintViolation();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -25,6 +25,8 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ElementKind;
|
||||
import javax.validation.Path;
|
||||
import javax.validation.ValidationException;
|
||||
import javax.validation.executable.ExecutableValidator;
|
||||
import javax.validation.metadata.BeanDescriptor;
|
||||
|
@ -57,7 +59,7 @@ import org.springframework.validation.SmartValidator;
|
|||
*/
|
||||
public class SpringValidatorAdapter implements SmartValidator, javax.validation.Validator {
|
||||
|
||||
private static final Set<String> internalAnnotationAttributes = new HashSet<>(3);
|
||||
private static final Set<String> internalAnnotationAttributes = new HashSet<>(4);
|
||||
|
||||
static {
|
||||
internalAnnotationAttributes.add("message");
|
||||
|
@ -176,7 +178,31 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
|||
* @see org.springframework.validation.FieldError#getField()
|
||||
*/
|
||||
protected String determineField(ConstraintViolation<Object> violation) {
|
||||
return violation.getPropertyPath().toString();
|
||||
Path path = violation.getPropertyPath();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (Path.Node node : path) {
|
||||
if (node.isInIterable()) {
|
||||
sb.append('[');
|
||||
Object index = node.getIndex();
|
||||
if (index == null) {
|
||||
index = node.getKey();
|
||||
}
|
||||
if (index != null) {
|
||||
sb.append(index);
|
||||
}
|
||||
sb.append(']');
|
||||
}
|
||||
String name = node.getName();
|
||||
if (name != null && node.getKind() == ElementKind.PROPERTY) {
|
||||
if (!first) {
|
||||
sb.append('.');
|
||||
}
|
||||
first = false;
|
||||
sb.append(name);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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,8 +31,6 @@ import org.springframework.tests.sample.beans.TestBean;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tested against Hibernate Validator 5.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class BeanValidationPostProcessorTests {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -35,8 +35,6 @@ import org.springframework.validation.annotation.Validated;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests against Hibernate Validator 5.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
|
|
@ -48,7 +48,6 @@ import static org.junit.Assert.*;
|
|||
/**
|
||||
* @author Kazuki Shimizu
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.3
|
||||
*/
|
||||
public class SpringValidatorAdapterTests {
|
||||
|
||||
|
@ -84,6 +83,7 @@ public class SpringValidatorAdapterTests {
|
|||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("password"), is(1));
|
||||
assertThat(errors.getFieldValue("password"), is("pass"));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("password"), Locale.ENGLISH),
|
||||
is("Size of Password is must be between 8 and 128"));
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ public class SpringValidatorAdapterTests {
|
|||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("password"), is(1));
|
||||
assertThat(errors.getFieldValue("password"), is("password"));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("password"), Locale.ENGLISH),
|
||||
is("Password must be same value with Password(Confirm)"));
|
||||
}
|
||||
|
@ -112,6 +113,7 @@ public class SpringValidatorAdapterTests {
|
|||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("email"), is(1));
|
||||
assertThat(errors.getFieldValue("email"), is("test@example.com"));
|
||||
assertThat(errors.getFieldErrorCount("confirmEmail"), is(1));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("email"), Locale.ENGLISH),
|
||||
is("email must be same value with confirmEmail"));
|
||||
|
@ -131,6 +133,7 @@ public class SpringValidatorAdapterTests {
|
|||
validatorAdapter.validate(testBean, errors);
|
||||
|
||||
assertThat(errors.getFieldErrorCount("email"), is(1));
|
||||
assertThat(errors.getFieldValue("email"), is("test@example.com"));
|
||||
assertThat(errors.getFieldErrorCount("confirmEmail"), is(1));
|
||||
assertThat(messageSource.getMessage(errors.getFieldError("email"), Locale.ENGLISH),
|
||||
is("email must be same value with confirmEmail"));
|
||||
|
@ -139,6 +142,7 @@ public class SpringValidatorAdapterTests {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Same(field = "password", comparingField = "confirmPassword")
|
||||
@Same(field = "email", comparingField = "confirmEmail")
|
||||
static class TestBean {
|
||||
|
|
|
@ -55,8 +55,6 @@ import static org.hamcrest.Matchers.*;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests against Hibernate Validator 5.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ValidatorFactoryTests {
|
||||
|
|
Loading…
Reference in New Issue