Jakarta EE 9 migration

Upgrades many dependency declarations; removes old EJB 2.x support and outdated Servlet-based integrations (Commons FileUpload, FreeMarker JSP support, Tiles).

Closes gh-22093
Closes gh-25354
Closes gh-26185
Closes gh-27423
See gh-27424
This commit is contained in:
Juergen Hoeller
2021-09-17 09:14:07 +02:00
parent 5822f1bf85
commit d84ca2ba90
1291 changed files with 4992 additions and 25322 deletions

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.cache.ehcache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.Configuration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManagerTests;
/**
* @author Stephane Nicoll
*/
public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests<EhCacheCacheManager> {
private CacheManager nativeCacheManager;
private EhCacheCacheManager cacheManager;
private EhCacheCacheManager transactionalCacheManager;
@BeforeEach
public void setup() {
nativeCacheManager = new CacheManager(new Configuration().name("EhCacheCacheManagerTests")
.defaultCache(new CacheConfiguration("default", 100)));
addNativeCache(CACHE_NAME);
cacheManager = new EhCacheCacheManager(nativeCacheManager);
cacheManager.setTransactionAware(false);
cacheManager.afterPropertiesSet();
transactionalCacheManager = new EhCacheCacheManager(nativeCacheManager);
transactionalCacheManager.setTransactionAware(true);
transactionalCacheManager.afterPropertiesSet();
}
@AfterEach
public void shutdown() {
nativeCacheManager.shutdown();
}
@Override
protected EhCacheCacheManager getCacheManager(boolean transactionAware) {
if (transactionAware) {
return transactionalCacheManager;
}
else {
return cacheManager;
}
}
@Override
protected Class<? extends org.springframework.cache.Cache> getCacheType() {
return EhCacheCache.class;
}
@Override
protected void addNativeCache(String cacheName) {
nativeCacheManager.addCache(cacheName);
}
@Override
protected void removeNativeCache(String cacheName) {
nativeCacheManager.removeCache(cacheName);
}
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.cache.ehcache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.Configuration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.testfixture.cache.AbstractCacheTests;
import org.springframework.core.testfixture.EnabledForTestGroups;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
/**
* @author Costin Leau
* @author Stephane Nicoll
* @author Juergen Hoeller
*/
public class EhCacheCacheTests extends AbstractCacheTests<EhCacheCache> {
private CacheManager cacheManager;
private Ehcache nativeCache;
private EhCacheCache cache;
@BeforeEach
public void setup() {
cacheManager = new CacheManager(new Configuration().name("EhCacheCacheTests")
.defaultCache(new CacheConfiguration("default", 100)));
nativeCache = new net.sf.ehcache.Cache(new CacheConfiguration(CACHE_NAME, 100));
cacheManager.addCache(nativeCache);
cache = new EhCacheCache(nativeCache);
}
@AfterEach
public void shutdown() {
cacheManager.shutdown();
}
@Override
protected EhCacheCache getCache() {
return cache;
}
@Override
protected Ehcache getNativeCache() {
return nativeCache;
}
@Test
@EnabledForTestGroups(LONG_RUNNING)
public void testExpiredElements() throws Exception {
String key = "brancusi";
String value = "constantin";
Element brancusi = new Element(key, value);
// ttl = 10s
brancusi.setTimeToLive(3);
nativeCache.put(brancusi);
assertThat(cache.get(key).get()).isEqualTo(value);
// wait for the entry to expire
Thread.sleep(5 * 1000);
assertThat(cache.get(key)).isNull();
}
}

View File

@@ -1,287 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.cache.ehcache;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.constructs.blocking.BlockingCache;
import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;
import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory;
import net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Juergen Hoeller
* @author Dmitriy Kopylenko
* @since 27.09.2004
*/
public class EhCacheSupportTests {
@Test
public void testBlankCacheManager() {
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
cacheManagerFb.setCacheManagerName("myCacheManager");
assertThat(cacheManagerFb.getObjectType()).isEqualTo(CacheManager.class);
assertThat(cacheManagerFb.isSingleton()).as("Singleton property").isTrue();
cacheManagerFb.afterPropertiesSet();
try {
CacheManager cm = cacheManagerFb.getObject();
assertThat(cm.getCacheNames().length == 0).as("Loaded CacheManager with no caches").isTrue();
Cache myCache1 = cm.getCache("myCache1");
assertThat(myCache1 == null).as("No myCache1 defined").isTrue();
}
finally {
cacheManagerFb.destroy();
}
}
@Test
public void testCacheManagerConflict() {
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
try {
cacheManagerFb.setCacheManagerName("myCacheManager");
assertThat(cacheManagerFb.getObjectType()).isEqualTo(CacheManager.class);
assertThat(cacheManagerFb.isSingleton()).as("Singleton property").isTrue();
cacheManagerFb.afterPropertiesSet();
CacheManager cm = cacheManagerFb.getObject();
assertThat(cm.getCacheNames().length == 0).as("Loaded CacheManager with no caches").isTrue();
Cache myCache1 = cm.getCache("myCache1");
assertThat(myCache1 == null).as("No myCache1 defined").isTrue();
EhCacheManagerFactoryBean cacheManagerFb2 = new EhCacheManagerFactoryBean();
cacheManagerFb2.setCacheManagerName("myCacheManager");
assertThatExceptionOfType(CacheException.class).as("because of naming conflict").isThrownBy(
cacheManagerFb2::afterPropertiesSet);
}
finally {
cacheManagerFb.destroy();
}
}
@Test
public void testAcceptExistingCacheManager() {
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
cacheManagerFb.setCacheManagerName("myCacheManager");
assertThat(cacheManagerFb.getObjectType()).isEqualTo(CacheManager.class);
assertThat(cacheManagerFb.isSingleton()).as("Singleton property").isTrue();
cacheManagerFb.afterPropertiesSet();
try {
CacheManager cm = cacheManagerFb.getObject();
assertThat(cm.getCacheNames().length == 0).as("Loaded CacheManager with no caches").isTrue();
Cache myCache1 = cm.getCache("myCache1");
assertThat(myCache1 == null).as("No myCache1 defined").isTrue();
EhCacheManagerFactoryBean cacheManagerFb2 = new EhCacheManagerFactoryBean();
cacheManagerFb2.setCacheManagerName("myCacheManager");
cacheManagerFb2.setAcceptExisting(true);
cacheManagerFb2.afterPropertiesSet();
CacheManager cm2 = cacheManagerFb2.getObject();
assertThat(cm2).isSameAs(cm);
cacheManagerFb2.destroy();
}
finally {
cacheManagerFb.destroy();
}
}
public void testCacheManagerFromConfigFile() {
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
cacheManagerFb.setConfigLocation(new ClassPathResource("testEhcache.xml", getClass()));
cacheManagerFb.setCacheManagerName("myCacheManager");
cacheManagerFb.afterPropertiesSet();
try {
CacheManager cm = cacheManagerFb.getObject();
assertThat(cm.getCacheNames().length == 1).as("Correct number of caches loaded").isTrue();
Cache myCache1 = cm.getCache("myCache1");
assertThat(myCache1.getCacheConfiguration().isEternal()).as("myCache1 is not eternal").isFalse();
assertThat(myCache1.getCacheConfiguration().getMaxEntriesLocalHeap() == 300).as("myCache1.maxElements == 300").isTrue();
}
finally {
cacheManagerFb.destroy();
}
}
@Test
public void testEhCacheFactoryBeanWithDefaultCacheManager() {
doTestEhCacheFactoryBean(false);
}
@Test
public void testEhCacheFactoryBeanWithExplicitCacheManager() {
doTestEhCacheFactoryBean(true);
}
private void doTestEhCacheFactoryBean(boolean useCacheManagerFb) {
Cache cache;
EhCacheManagerFactoryBean cacheManagerFb = null;
boolean cacheManagerFbInitialized = false;
try {
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
Class<? extends Ehcache> objectType = cacheFb.getObjectType();
assertThat(Ehcache.class.isAssignableFrom(objectType)).isTrue();
assertThat(cacheFb.isSingleton()).as("Singleton property").isTrue();
if (useCacheManagerFb) {
cacheManagerFb = new EhCacheManagerFactoryBean();
cacheManagerFb.setConfigLocation(new ClassPathResource("testEhcache.xml", getClass()));
cacheManagerFb.setCacheManagerName("cache");
cacheManagerFb.afterPropertiesSet();
cacheManagerFbInitialized = true;
cacheFb.setCacheManager(cacheManagerFb.getObject());
}
cacheFb.setCacheName("myCache1");
cacheFb.afterPropertiesSet();
cache = (Cache) cacheFb.getObject();
Class<? extends Ehcache> objectType2 = cacheFb.getObjectType();
assertThat(objectType2).isSameAs(objectType);
CacheConfiguration config = cache.getCacheConfiguration();
assertThat(cache.getName()).isEqualTo("myCache1");
if (useCacheManagerFb){
assertThat(config.getMaxEntriesLocalHeap()).as("myCache1.maxElements").isEqualTo(300);
}
else {
assertThat(config.getMaxEntriesLocalHeap()).as("myCache1.maxElements").isEqualTo(10000);
}
// Cache region is not defined. Should create one with default properties.
cacheFb = new EhCacheFactoryBean();
if (useCacheManagerFb) {
cacheFb.setCacheManager(cacheManagerFb.getObject());
}
cacheFb.setCacheName("undefinedCache");
cacheFb.afterPropertiesSet();
cache = (Cache) cacheFb.getObject();
config = cache.getCacheConfiguration();
assertThat(cache.getName()).isEqualTo("undefinedCache");
assertThat(config.getMaxEntriesLocalHeap() == 10000).as("default maxElements is correct").isTrue();
assertThat(config.isEternal()).as("default eternal is correct").isFalse();
assertThat(config.getTimeToLiveSeconds() == 120).as("default timeToLive is correct").isTrue();
assertThat(config.getTimeToIdleSeconds() == 120).as("default timeToIdle is correct").isTrue();
assertThat(config.getDiskExpiryThreadIntervalSeconds() == 120).as("default diskExpiryThreadIntervalSeconds is correct").isTrue();
// overriding the default properties
cacheFb = new EhCacheFactoryBean();
if (useCacheManagerFb) {
cacheFb.setCacheManager(cacheManagerFb.getObject());
}
cacheFb.setBeanName("undefinedCache2");
cacheFb.setMaxEntriesLocalHeap(5);
cacheFb.setTimeToLive(8);
cacheFb.setTimeToIdle(7);
cacheFb.setDiskExpiryThreadIntervalSeconds(10);
cacheFb.afterPropertiesSet();
cache = (Cache) cacheFb.getObject();
config = cache.getCacheConfiguration();
assertThat(cache.getName()).isEqualTo("undefinedCache2");
assertThat(config.getMaxEntriesLocalHeap() == 5).as("overridden maxElements is correct").isTrue();
assertThat(config.getTimeToLiveSeconds() == 8).as("default timeToLive is correct").isTrue();
assertThat(config.getTimeToIdleSeconds() == 7).as("default timeToIdle is correct").isTrue();
assertThat(config.getDiskExpiryThreadIntervalSeconds() == 10).as("overridden diskExpiryThreadIntervalSeconds is correct").isTrue();
}
finally {
if (cacheManagerFbInitialized) {
cacheManagerFb.destroy();
}
else {
CacheManager.getInstance().shutdown();
}
}
}
@Test
public void testEhCacheFactoryBeanWithBlockingCache() {
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
cacheManagerFb.afterPropertiesSet();
try {
CacheManager cm = cacheManagerFb.getObject();
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
cacheFb.setCacheManager(cm);
cacheFb.setCacheName("myCache1");
cacheFb.setBlocking(true);
assertThat(BlockingCache.class).isEqualTo(cacheFb.getObjectType());
cacheFb.afterPropertiesSet();
Ehcache myCache1 = cm.getEhcache("myCache1");
boolean condition = myCache1 instanceof BlockingCache;
assertThat(condition).isTrue();
}
finally {
cacheManagerFb.destroy();
}
}
@Test
public void testEhCacheFactoryBeanWithSelfPopulatingCache() {
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
cacheManagerFb.afterPropertiesSet();
try {
CacheManager cm = cacheManagerFb.getObject();
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
cacheFb.setCacheManager(cm);
cacheFb.setCacheName("myCache1");
cacheFb.setCacheEntryFactory(key -> key);
assertThat(SelfPopulatingCache.class).isEqualTo(cacheFb.getObjectType());
cacheFb.afterPropertiesSet();
Ehcache myCache1 = cm.getEhcache("myCache1");
boolean condition = myCache1 instanceof SelfPopulatingCache;
assertThat(condition).isTrue();
assertThat(myCache1.get("myKey1").getObjectValue()).isEqualTo("myKey1");
}
finally {
cacheManagerFb.destroy();
}
}
@Test
public void testEhCacheFactoryBeanWithUpdatingSelfPopulatingCache() {
EhCacheManagerFactoryBean cacheManagerFb = new EhCacheManagerFactoryBean();
cacheManagerFb.afterPropertiesSet();
try {
CacheManager cm = cacheManagerFb.getObject();
EhCacheFactoryBean cacheFb = new EhCacheFactoryBean();
cacheFb.setCacheManager(cm);
cacheFb.setCacheName("myCache1");
cacheFb.setCacheEntryFactory(new UpdatingCacheEntryFactory() {
@Override
public Object createEntry(Object key) {
return key;
}
@Override
public void updateEntryValue(Object key, Object value) {
}
});
assertThat(UpdatingSelfPopulatingCache.class).isEqualTo(cacheFb.getObjectType());
cacheFb.afterPropertiesSet();
Ehcache myCache1 = cm.getEhcache("myCache1");
boolean condition = myCache1 instanceof UpdatingSelfPopulatingCache;
assertThat(condition).isTrue();
assertThat(myCache1.get("myKey1").getObjectValue()).isEqualTo("myKey1");
}
finally {
cacheManagerFb.destroy();
}
}
}

View File

@@ -1,35 +0,0 @@
/*
* 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
*
* https://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.cache.jcache;
import javax.cache.Caching;
import javax.cache.spi.CachingProvider;
/**
* Just here to be run against EHCache 3, whereas the original JCacheEhCacheAnnotationTests
* runs against EhCache 2.x with the EhCache-JCache add-on.
*
* @author Juergen Hoeller
*/
public class JCacheEhCache3AnnotationTests extends JCacheEhCacheAnnotationTests {
@Override
protected CachingProvider getCachingProvider() {
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
}
}

View File

@@ -1,35 +0,0 @@
/*
* 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
*
* https://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.cache.jcache;
import javax.cache.Caching;
import javax.cache.spi.CachingProvider;
/**
* Just here to be run against EHCache 3, whereas the original JCacheEhCacheAnnotationTests
* runs against EhCache 2.x with the EhCache-JCache add-on.
*
* @author Stephane Nicoll
*/
public class JCacheEhCache3ApiTests extends JCacheEhCacheApiTests {
@Override
protected CachingProvider getCachingProvider() {
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
}
}

View File

@@ -64,7 +64,7 @@ public class JCacheEhCacheAnnotationTests extends AbstractCacheAnnotationTests {
}
protected CachingProvider getCachingProvider() {
return Caching.getCachingProvider("org.ehcache.jcache.JCacheCachingProvider");
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
}
@AfterEach

View File

@@ -54,7 +54,7 @@ public class JCacheEhCacheApiTests extends AbstractValueAdaptingCacheTests<JCach
}
protected CachingProvider getCachingProvider() {
return Caching.getCachingProvider("org.ehcache.jcache.JCacheCachingProvider");
return Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
}
@AfterEach

View File

@@ -24,18 +24,17 @@ import java.util.GregorianCalendar;
import java.util.List;
import java.util.Properties;
import javax.activation.FileTypeMap;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import jakarta.activation.FileTypeMap;
import jakarta.mail.Address;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.NoSuchProviderException;
import jakarta.mail.Session;
import jakarta.mail.Transport;
import jakarta.mail.URLName;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import org.junit.jupiter.api.Test;
import org.springframework.mail.MailParseException;

View File

@@ -1,155 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.validation.beanvalidation.BeanValidationPostProcessor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @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));
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(ac::refresh)
.havingRootCause()
.withMessageContainingAll("testBean", "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);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(ac::refresh)
.havingRootCause()
.withMessageContainingAll("stringValue", "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() {
assertThat(this.testBean).as("Shouldn't be here after constraint checking").isNotNull();
}
}
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();
}
}
}

View File

@@ -1,218 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.ValidationException;
import javax.validation.Validator;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
import javax.validation.groups.Default;
import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
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.CustomValidatorBean;
import org.springframework.validation.beanvalidation.MethodValidationInterceptor;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Juergen Hoeller
*/
public class MethodValidationTests {
@Test
@SuppressWarnings("unchecked")
public void testMethodValidationInterceptor() {
MyValidBean bean = new MyValidBean();
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvice(new MethodValidationInterceptor());
proxyFactory.addAdvisor(new AsyncAnnotationAdvisor());
doTestProxyValidation((MyValidInterface<String>) proxyFactory.getProxy());
}
@Test
@SuppressWarnings("unchecked")
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();
}
private void doTestProxyValidation(MyValidInterface<String> proxy) {
assertThat(proxy.myValidMethod("value", 5)).isNotNull();
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
proxy.myValidMethod("value", 15));
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
proxy.myValidMethod(null, 5));
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
proxy.myValidMethod("value", 0));
proxy.myValidAsyncMethod("value", 5);
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
proxy.myValidAsyncMethod("value", 15));
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
proxy.myValidAsyncMethod(null, 5));
assertThat(proxy.myGenericMethod("myValue")).isEqualTo("myValue");
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
proxy.myGenericMethod(null));
}
@Test
public void testLazyValidatorForMethodValidation() {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfig.class, CustomValidatorBean.class,
MyValidBean.class, MyValidFactoryBean.class);
ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
}
@Test
public void testLazyValidatorForMethodValidationWithProxyTargetClass() {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfigWithProxyTargetClass.class, CustomValidatorBean.class,
MyValidBean.class, MyValidFactoryBean.class);
ctx.getBeansOfType(MyValidInterface.class).values().forEach(bean -> bean.myValidMethod("value", 5));
}
@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;
}
}
@MyStereotype
public static class MyValidFactoryBean implements FactoryBean<String>, MyValidInterface<String> {
@Override
public String getObject() {
return null;
}
@Override
public Class<?> getObjectType() {
return String.class;
}
@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 {
}
@Configuration
public static class LazyMethodValidationConfig {
@Bean
public static MethodValidationPostProcessor methodValidationPostProcessor(@Lazy Validator validator) {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
postProcessor.setValidator(validator);
return postProcessor;
}
}
@Configuration
public static class LazyMethodValidationConfigWithProxyTargetClass {
@Bean
public static MethodValidationPostProcessor methodValidationPostProcessor(@Lazy Validator validator) {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
postProcessor.setValidator(validator);
postProcessor.setProxyTargetClass(true);
return postProcessor;
}
}
}

View File

@@ -1,563 +0,0 @@
/*
* Copyright 2002-2020 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
*
* https://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.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
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.Validation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.support.StaticMessageSource;
import org.springframework.core.testfixture.io.SerializationTestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @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();
@BeforeEach
public void setupSpringValidatorAdapter() {
messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} must be between {2} and {1}");
messageSource.addMessage("Same", Locale.ENGLISH, "{2} must be same value as {1}");
messageSource.addMessage("password", Locale.ENGLISH, "Password");
messageSource.addMessage("confirmPassword", Locale.ENGLISH, "Password(Confirm)");
}
@Test
public void testUnwrap() {
Validator nativeValidator = validatorAdapter.unwrap(Validator.class);
assertThat(nativeValidator).isSameAs(this.nativeValidator);
}
@Test // SPR-13406
public void testNoStringArgumentValue() throws Exception {
TestBean testBean = new TestBean();
testBean.setPassword("pass");
testBean.setConfirmPassword("pass");
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
validatorAdapter.validate(testBean, errors);
assertThat(errors.getFieldErrorCount("password")).isEqualTo(1);
assertThat(errors.getFieldValue("password")).isEqualTo("pass");
FieldError error = errors.getFieldError("password");
assertThat(error).isNotNull();
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).isEqualTo("Size of Password must be between 8 and 128");
assertThat(error.contains(ConstraintViolation.class)).isTrue();
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("password");
assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString())).isEqualTo(error.toString());
}
@Test // SPR-13406
public void testApplyMessageSourceResolvableToStringArgumentValueWithResolvedLogicalFieldName() throws Exception {
TestBean testBean = new TestBean();
testBean.setPassword("password");
testBean.setConfirmPassword("PASSWORD");
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
validatorAdapter.validate(testBean, errors);
assertThat(errors.getFieldErrorCount("password")).isEqualTo(1);
assertThat(errors.getFieldValue("password")).isEqualTo("password");
FieldError error = errors.getFieldError("password");
assertThat(error).isNotNull();
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).isEqualTo("Password must be same value as Password(Confirm)");
assertThat(error.contains(ConstraintViolation.class)).isTrue();
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("password");
assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString())).isEqualTo(error.toString());
}
@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")).isEqualTo(1);
assertThat(errors.getFieldValue("email")).isEqualTo("test@example.com");
assertThat(errors.getFieldErrorCount("confirmEmail")).isEqualTo(1);
FieldError error1 = errors.getFieldError("email");
FieldError error2 = errors.getFieldError("confirmEmail");
assertThat(error1).isNotNull();
assertThat(error2).isNotNull();
assertThat(messageSource.getMessage(error1, Locale.ENGLISH)).isEqualTo("email must be same value as confirmEmail");
assertThat(messageSource.getMessage(error2, Locale.ENGLISH)).isEqualTo("Email required");
assertThat(error1.contains(ConstraintViolation.class)).isTrue();
assertThat(error1.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("email");
assertThat(error2.contains(ConstraintViolation.class)).isTrue();
assertThat(error2.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("confirmEmail");
}
@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")).isEqualTo(1);
assertThat(errors.getFieldValue("email")).isEqualTo("test@example.com");
assertThat(errors.getFieldErrorCount("confirmEmail")).isEqualTo(1);
FieldError error1 = errors.getFieldError("email");
FieldError error2 = errors.getFieldError("confirmEmail");
assertThat(error1).isNotNull();
assertThat(error2).isNotNull();
assertThat(messageSource.getMessage(error1, Locale.ENGLISH)).isEqualTo("email must be same value as confirmEmail");
assertThat(messageSource.getMessage(error2, Locale.ENGLISH)).isEqualTo("Email required");
assertThat(error1.contains(ConstraintViolation.class)).isTrue();
assertThat(error1.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("email");
assertThat(error2.contains(ConstraintViolation.class)).isTrue();
assertThat(error2.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("confirmEmail");
}
@Test
public void testPatternMessage() {
TestBean testBean = new TestBean();
testBean.setEmail("X");
testBean.setConfirmEmail("X");
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
validatorAdapter.validate(testBean, errors);
assertThat(errors.getFieldErrorCount("email")).isEqualTo(1);
assertThat(errors.getFieldValue("email")).isEqualTo("X");
FieldError error = errors.getFieldError("email");
assertThat(error).isNotNull();
assertThat(messageSource.getMessage(error, Locale.ENGLISH)).contains("[\\w.'-]{1,}@[\\w.'-]{1,}");
assertThat(error.contains(ConstraintViolation.class)).isTrue();
assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString()).isEqualTo("email");
}
@Test // SPR-16177
public void testWithList() {
Parent parent = new Parent();
parent.setName("Parent whit list");
parent.getChildList().addAll(createChildren(parent));
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(parent, "parent");
validatorAdapter.validate(parent, errors);
assertThat(errors.getErrorCount() > 0).isTrue();
}
@Test // SPR-16177
public void testWithSet() {
Parent parent = new Parent();
parent.setName("Parent with set");
parent.getChildSet().addAll(createChildren(parent));
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(parent, "parent");
validatorAdapter.validate(parent, errors);
assertThat(errors.getErrorCount() > 0).isTrue();
}
private List<Child> createChildren(Parent parent) {
Child child1 = new Child();
child1.setName("Child1");
child1.setAge(null);
child1.setParent(parent);
Child child2 = new Child();
child2.setName(null);
child2.setAge(17);
child2.setParent(parent);
return Arrays.asList(child1, child2);
}
@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]")).isEqualTo(1);
assertThat(errors.getFieldValue("property[4]")).isNull();
}
@Test // SPR-15839
public void testMapValueConstraint() {
Map<String, String> property = new HashMap<>();
property.put("no value can be", null);
BeanWithMapEntryConstraint bean = new BeanWithMapEntryConstraint();
bean.setProperty(property);
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(bean, "bean");
validatorAdapter.validate(bean, errors);
assertThat(errors.getFieldErrorCount("property[no value can be]")).isEqualTo(1);
assertThat(errors.getFieldValue("property[no value can be]")).isNull();
}
@Test // SPR-15839
public void testMapEntryConstraint() {
Map<String, String> property = new HashMap<>();
property.put(null, null);
BeanWithMapEntryConstraint bean = new BeanWithMapEntryConstraint();
bean.setProperty(property);
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(bean, "bean");
validatorAdapter.validate(bean, errors);
assertThat(errors.hasFieldErrors("property[]")).isTrue();
assertThat(errors.getFieldValue("property[]")).isNull();
}
@Same(field = "password", comparingField = "confirmPassword")
@Same(field = "email", comparingField = "confirmEmail")
static class TestBean {
@Size(min = 8, max = 128)
private String password;
private String confirmPassword;
@Pattern(regexp = "[\\w.'-]{1,}@[\\w.'-]{1,}")
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({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.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({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
Same[] value();
}
}
@Documented
@Inherited
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface SameGroup {
Same[] value();
}
public static class SameValidator implements ConstraintValidator<Same, Object> {
private String field;
private String comparingField;
private String message;
@Override
public void initialize(Same constraintAnnotation) {
field = constraintAnnotation.field();
comparingField = constraintAnnotation.comparingField();
message = constraintAnnotation.message();
}
@Override
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 static class Parent {
private Integer id;
@NotNull
private String name;
@Valid
private Set<Child> childSet = new LinkedHashSet<>();
@Valid
private List<Child> childList = new ArrayList<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Child> getChildSet() {
return childSet;
}
public void setChildSet(Set<Child> childSet) {
this.childSet = childSet;
}
public List<Child> getChildList() {
return childList;
}
public void setChildList(List<Child> childList) {
this.childList = childList;
}
}
@AnythingValid
public static class Child {
private Integer id;
@NotNull
private String name;
@NotNull
private Integer age;
@NotNull
private Parent parent;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
@Constraint(validatedBy = AnythingValidator.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnythingValid {
String message() default "{AnythingValid.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public static class AnythingValidator implements ConstraintValidator<AnythingValid, Object> {
private static final String ID = "id";
@Override
public void initialize(AnythingValid constraintAnnotation) {
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
List<Field> fieldsErrors = new ArrayList<>();
Arrays.asList(value.getClass().getDeclaredFields()).forEach(field -> {
field.setAccessible(true);
try {
if (!field.getName().equals(ID) && field.get(value) == null) {
fieldsErrors.add(field);
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
.addPropertyNode(field.getName())
.addConstraintViolation();
}
}
catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
});
return fieldsErrors.isEmpty();
}
}
public class BeanWithListElementConstraint {
@Valid
private List<@NotNull String> property;
public List<String> getProperty() {
return property;
}
public void setProperty(List<String> property) {
this.property = property;
}
}
public class BeanWithMapEntryConstraint {
@Valid
private Map<@NotNull String, @NotNull String> property;
public Map<String, String> getProperty() {
return property;
}
public void setProperty(Map<String, String> property) {
this.property = property;
}
}
}

View File

@@ -1,505 +0,0 @@
/*
* Copyright 2002-2020 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
*
* https://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.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
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.jupiter.api.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.assertj.core.api.Assertions.assertThat;
/**
* @author Juergen Hoeller
*/
@SuppressWarnings("resource")
public class ValidatorFactoryTests {
@Test
@SuppressWarnings("cast")
public void testSimpleValidation() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
assertThat(result.size()).isEqualTo(2);
for (ConstraintViolation<ValidPerson> cv : result) {
String path = cv.getPropertyPath().toString();
assertThat(path).matches(actual -> "name".equals(actual) || "address.street".equals(actual));
assertThat(cv.getConstraintDescriptor().getAnnotation()).isInstanceOf(NotNull.class);
}
Validator nativeValidator = validator.unwrap(Validator.class);
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
validator.destroy();
}
@Test
@SuppressWarnings("cast")
public void testSimpleValidationWithCustomProvider() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setProviderClass(HibernateValidator.class);
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
assertThat(result.size()).isEqualTo(2);
for (ConstraintViolation<ValidPerson> cv : result) {
String path = cv.getPropertyPath().toString();
assertThat(path).matches(actual -> "name".equals(actual) || "address.street".equals(actual));
assertThat(cv.getConstraintDescriptor().getAnnotation()).isInstanceOf(NotNull.class);
}
Validator nativeValidator = validator.unwrap(Validator.class);
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
validator.destroy();
}
@Test
public void testSimpleValidationWithClassLevel() {
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);
assertThat(result.size()).isEqualTo(1);
Iterator<ConstraintViolation<ValidPerson>> iterator = result.iterator();
ConstraintViolation<?> cv = iterator.next();
assertThat(cv.getPropertyPath().toString()).isEqualTo("");
assertThat(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid).isTrue();
}
@Test
public void testSpringValidationFieldType() {
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);
assertThat(errors.getErrorCount()).isEqualTo(1);
assertThat(errors.getFieldError("address").getRejectedValue()).isInstanceOf(ValidAddress.class);
}
@Test
public void testSpringValidation() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
validator.validate(person, result);
assertThat(result.getErrorCount()).isEqualTo(2);
FieldError fieldError = result.getFieldError("name");
assertThat(fieldError.getField()).isEqualTo("name");
List<String> errorCodes = Arrays.asList(fieldError.getCodes());
assertThat(errorCodes.size()).isEqualTo(4);
assertThat(errorCodes.contains("NotNull.person.name")).isTrue();
assertThat(errorCodes.contains("NotNull.name")).isTrue();
assertThat(errorCodes.contains("NotNull.java.lang.String")).isTrue();
assertThat(errorCodes.contains("NotNull")).isTrue();
fieldError = result.getFieldError("address.street");
assertThat(fieldError.getField()).isEqualTo("address.street");
errorCodes = Arrays.asList(fieldError.getCodes());
assertThat(errorCodes.size()).isEqualTo(5);
assertThat(errorCodes.contains("NotNull.person.address.street")).isTrue();
assertThat(errorCodes.contains("NotNull.address.street")).isTrue();
assertThat(errorCodes.contains("NotNull.street")).isTrue();
assertThat(errorCodes.contains("NotNull.java.lang.String")).isTrue();
assertThat(errorCodes.contains("NotNull")).isTrue();
}
@Test
public void testSpringValidationWithClassLevel() {
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);
assertThat(result.getErrorCount()).isEqualTo(1);
ObjectError globalError = result.getGlobalError();
List<String> errorCodes = Arrays.asList(globalError.getCodes());
assertThat(errorCodes.size()).isEqualTo(2);
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
}
@Test
public void testSpringValidationWithAutowiredValidator() {
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);
assertThat(result.getErrorCount()).isEqualTo(1);
ObjectError globalError = result.getGlobalError();
List<String> errorCodes = Arrays.asList(globalError.getCodes());
assertThat(errorCodes.size()).isEqualTo(2);
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
ctx.close();
}
@Test
public void testSpringValidationWithErrorInListElement() {
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);
assertThat(result.getErrorCount()).isEqualTo(3);
FieldError fieldError = result.getFieldError("name");
assertThat(fieldError.getField()).isEqualTo("name");
fieldError = result.getFieldError("address.street");
assertThat(fieldError.getField()).isEqualTo("address.street");
fieldError = result.getFieldError("addressList[0].street");
assertThat(fieldError.getField()).isEqualTo("addressList[0].street");
}
@Test
public void testSpringValidationWithErrorInSetElement() {
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);
assertThat(result.getErrorCount()).isEqualTo(3);
FieldError fieldError = result.getFieldError("name");
assertThat(fieldError.getField()).isEqualTo("name");
fieldError = result.getFieldError("address.street");
assertThat(fieldError.getField()).isEqualTo("address.street");
fieldError = result.getFieldError("addressSet[].street");
assertThat(fieldError.getField()).isEqualTo("addressSet[].street");
}
@Test
public void testInnerBeanValidation() {
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");
assertThat(rejected).isNull();
}
@Test
public void testValidationWithOptionalField() {
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");
assertThat(rejected).isNull();
}
@Test
public void testListValidation() {
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]");
assertThat(fieldError).isNotNull();
assertThat(fieldError.getRejectedValue()).isEqualTo("X");
assertThat(errors.getFieldValue("list[1]")).isEqualTo("X");
}
@NameAddressValid
public static class ValidPerson {
@NotNull
private String name;
@Valid
private ValidAddress address = new ValidAddress();
@Valid
private List<ValidAddress> addressList = new ArrayList<>();
@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) {
assertThat(this.environment).isNotNull();
}
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 ArrayList<>();
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;
}
}
}