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

@@ -16,9 +16,8 @@
package org.springframework.beans.factory.annotation;
import javax.inject.Inject;
import javax.inject.Named;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

View File

@@ -21,10 +21,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Qualifier;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Qualifier;
import org.junit.jupiter.api.Test;
import org.springframework.aop.scope.ScopedProxyUtils;
@@ -40,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Integration tests for handling JSR-303 {@link javax.inject.Qualifier} annotations.
* Integration tests for handling JSR-303 {@link jakarta.inject.Qualifier} annotations.
*
* @author Juergen Hoeller
* @since 3.0

View File

@@ -16,8 +16,7 @@
package org.springframework.context.annotation;
import javax.annotation.PreDestroy;
import jakarta.annotation.PreDestroy;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@@ -18,11 +18,10 @@ package org.springframework.context.annotation;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.EJB;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.annotation.Resource;
import jakarta.ejb.EJB;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeansException;

View File

@@ -16,8 +16,7 @@
package org.springframework.context.annotation;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -23,8 +23,7 @@ import java.lang.annotation.Target;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@@ -16,8 +16,7 @@
package org.springframework.context.annotation;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -26,8 +26,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.Properties;
import javax.inject.Inject;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanDefinitionStoreException;

View File

@@ -20,9 +20,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.Test;
@@ -49,8 +48,8 @@ import static org.assertj.core.api.Assertions.assertThat;
* <li>{@link InitializingBean} &amp; {@link DisposableBean} interfaces</li>
* <li>Custom {@link RootBeanDefinition#getInitMethodName() init} &amp;
* {@link RootBeanDefinition#getDestroyMethodName() destroy} methods</li>
* <li>JSR 250's {@link javax.annotation.PostConstruct @PostConstruct} &amp;
* {@link javax.annotation.PreDestroy @PreDestroy} annotations</li>
* <li>JSR 250's {@link jakarta.annotation.PostConstruct @PostConstruct} &amp;
* {@link jakarta.annotation.PreDestroy @PreDestroy} annotations</li>
* </ul>
*
* @author Sam Brannen

View File

@@ -22,8 +22,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Optional;
import javax.inject.Provider;
import jakarta.inject.Provider;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactory;

View File

@@ -22,9 +22,8 @@ import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import javax.annotation.Resource;
import javax.inject.Provider;
import jakarta.annotation.Resource;
import jakarta.inject.Provider;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanClassLoaderAware;

View File

@@ -16,8 +16,7 @@
package org.springframework.context.annotation.configuration;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

View File

@@ -16,7 +16,7 @@
package org.springframework.context.annotation6;
import javax.inject.Named;
import jakarta.inject.Named;
@Named
public class Jsr330NamedForScanning {

View File

@@ -30,9 +30,8 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

View File

@@ -1,207 +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.ejb.access;
import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.naming.Context;
import javax.naming.NamingException;
import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.jndi.JndiTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
*/
public class LocalSlsbInvokerInterceptorTests {
/**
* Test that it performs the correct lookup.
*/
@Test
public void testPerformsLookup() throws Exception {
LocalInterfaceWithBusinessMethods ejb = mock(LocalInterfaceWithBusinessMethods.class);
String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
configuredInterceptor(mockContext, jndiName);
verify(mockContext).close();
}
@Test
public void testLookupFailure() throws Exception {
final NamingException nex = new NamingException();
final String jndiName= "foobar";
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) throws NamingException {
assertThat(jndiName.equals(name)).isTrue();
throw nex;
}
};
LocalSlsbInvokerInterceptor si = new LocalSlsbInvokerInterceptor();
si.setJndiName("foobar");
// default resourceRef=false should cause this to fail, as java:/comp/env will not
// automatically be added
si.setJndiTemplate(jt);
assertThatExceptionOfType(NamingException.class)
.isThrownBy(si::afterPropertiesSet)
.isSameAs(nex);
}
@Test
public void testInvokesMethodOnEjbInstance() throws Exception {
Object retVal = new Object();
LocalInterfaceWithBusinessMethods ejb = mock(LocalInterfaceWithBusinessMethods.class);
given(ejb.targetMethod()).willReturn(retVal);
String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
LocalSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
ProxyFactory pf = new ProxyFactory(new Class<?>[] { BusinessMethods.class });
pf.addAdvice(si);
BusinessMethods target = (BusinessMethods) pf.getProxy();
assertThat(target.targetMethod() == retVal).isTrue();
verify(mockContext).close();
verify(ejb).remove();
}
@Test
public void testInvokesMethodOnEjbInstanceWithSeparateBusinessMethods() throws Exception {
Object retVal = new Object();
LocalInterface ejb = mock(LocalInterface.class);
given(ejb.targetMethod()).willReturn(retVal);
String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
LocalSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
ProxyFactory pf = new ProxyFactory(new Class<?>[] { BusinessMethods.class });
pf.addAdvice(si);
BusinessMethods target = (BusinessMethods) pf.getProxy();
assertThat(target.targetMethod() == retVal).isTrue();
verify(mockContext).close();
verify(ejb).remove();
}
private void testException(Exception expected) throws Exception {
LocalInterfaceWithBusinessMethods ejb = mock(LocalInterfaceWithBusinessMethods.class);
given(ejb.targetMethod()).willThrow(expected);
String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
LocalSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
ProxyFactory pf = new ProxyFactory(new Class<?>[] { LocalInterfaceWithBusinessMethods.class });
pf.addAdvice(si);
LocalInterfaceWithBusinessMethods target = (LocalInterfaceWithBusinessMethods) pf.getProxy();
assertThatExceptionOfType(Exception.class)
.isThrownBy(target::targetMethod)
.isSameAs(expected);
verify(mockContext).close();
}
@Test
public void testApplicationException() throws Exception {
testException(new ApplicationException());
}
protected Context mockContext(final String jndiName, final Object ejbInstance)
throws Exception {
SlsbHome mockHome = mock(SlsbHome.class);
given(mockHome.create()).willReturn((LocalInterface)ejbInstance);
Context mockCtx = mock(Context.class);
given(mockCtx.lookup("java:comp/env/" + jndiName)).willReturn(mockHome);
return mockCtx;
}
protected LocalSlsbInvokerInterceptor configuredInterceptor(final Context mockCtx, final String jndiName)
throws Exception {
LocalSlsbInvokerInterceptor si = new LocalSlsbInvokerInterceptor();
si.setJndiTemplate(new JndiTemplate() {
@Override
protected Context createInitialContext() throws NamingException {
return mockCtx;
}
});
si.setJndiName(jndiName);
si.setResourceRef(true);
si.afterPropertiesSet();
return si;
}
/**
* Needed so that we can mock the create() method.
*/
private interface SlsbHome extends EJBLocalHome {
LocalInterface create() throws CreateException;
}
private interface BusinessMethods {
Object targetMethod() throws ApplicationException;
}
private interface LocalInterface extends EJBLocalObject {
Object targetMethod() throws ApplicationException;
}
private interface LocalInterfaceWithBusinessMethods extends LocalInterface, BusinessMethods {
}
@SuppressWarnings("serial")
private class ApplicationException extends Exception {
public ApplicationException() {
super("appException");
}
}
}

View File

@@ -1,197 +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.ejb.access;
import java.lang.reflect.Proxy;
import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.naming.NamingException;
import org.junit.jupiter.api.Test;
import org.springframework.jndi.JndiTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 21.05.2003
*/
public class LocalStatelessSessionProxyFactoryBeanTests {
@Test
public void testInvokesMethod() throws Exception {
final int value = 11;
final String jndiName = "foo";
MyEjb myEjb = mock(MyEjb.class);
given(myEjb.getValue()).willReturn(value);
final MyHome home = mock(MyHome.class);
given(home.create()).willReturn(myEjb);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) throws NamingException {
// parameterize
assertThat(name.equals("java:comp/env/" + jndiName)).isTrue();
return home;
}
};
LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
fb.setResourceRef(true);
fb.setBusinessInterface(MyBusinessMethods.class);
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThat(mbm.getValue() == value).isTrue();
verify(myEjb).remove();
}
@Test
public void testInvokesMethodOnEjb3StyleBean() throws Exception {
final int value = 11;
final String jndiName = "foo";
final MyEjb myEjb = mock(MyEjb.class);
given(myEjb.getValue()).willReturn(value);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) throws NamingException {
// parameterize
assertThat(name.equals("java:comp/env/" + jndiName)).isTrue();
return myEjb;
}
};
LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
fb.setResourceRef(true);
fb.setBusinessInterface(MyBusinessMethods.class);
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThat(mbm.getValue() == value).isTrue();
}
@Test
public void testCreateException() throws Exception {
final String jndiName = "foo";
final CreateException cex = new CreateException();
final MyHome home = mock(MyHome.class);
given(home.create()).willThrow(cex);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) throws NamingException {
// parameterize
assertThat(name.equals(jndiName)).isTrue();
return home;
}
};
LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
fb.setResourceRef(false); // no java:comp/env prefix
fb.setBusinessInterface(MyBusinessMethods.class);
assertThat(MyBusinessMethods.class).isEqualTo(fb.getBusinessInterface());
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThatExceptionOfType(EjbAccessException.class).isThrownBy(
mbm::getValue)
.withCause(cex);
}
@Test
public void testNoBusinessInterfaceSpecified() throws Exception {
// Will do JNDI lookup to get home but won't call create
// Could actually try to figure out interface from create?
final String jndiName = "foo";
final MyHome home = mock(MyHome.class);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) throws NamingException {
// parameterize
assertThat(name.equals("java:comp/env/" + jndiName)).isTrue();
return home;
}
};
LocalStatelessSessionProxyFactoryBean fb = new LocalStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
fb.setResourceRef(true);
// Don't set business interface
fb.setJndiTemplate(jt);
// Check it's a singleton
assertThat(fb.isSingleton()).isTrue();
assertThatIllegalArgumentException().isThrownBy(
fb::afterPropertiesSet)
.withMessageContaining("businessInterface");
// Expect no methods on home
verifyNoInteractions(home);
}
public interface MyHome extends EJBLocalHome {
MyBusinessMethods create() throws CreateException;
}
public interface MyBusinessMethods {
int getValue();
}
public interface MyEjb extends EJBLocalObject, MyBusinessMethods {
}
}

View File

@@ -1,349 +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.ejb.access;
import java.rmi.ConnectException;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.naming.Context;
import javax.naming.NamingException;
import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.jndi.JndiTemplate;
import org.springframework.remoting.RemoteAccessException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
*/
public class SimpleRemoteSlsbInvokerInterceptorTests {
private Context mockContext(
String jndiName, RemoteInterface ejbInstance)
throws Exception {
SlsbHome mockHome = mock(SlsbHome.class);
given(mockHome.create()).willReturn(ejbInstance);
Context mockCtx = mock(Context.class);
given(mockCtx.lookup("java:comp/env/" + jndiName)).willReturn(mockHome);
return mockCtx;
}
private SimpleRemoteSlsbInvokerInterceptor configuredInterceptor(
final Context mockCtx, String jndiName) throws Exception {
SimpleRemoteSlsbInvokerInterceptor si = createInterceptor();
si.setJndiTemplate(new JndiTemplate() {
@Override
protected Context createInitialContext() {
return mockCtx;
}
});
si.setResourceRef(true);
si.setJndiName(jndiName);
return si;
}
protected SimpleRemoteSlsbInvokerInterceptor createInterceptor() {
return new SimpleRemoteSlsbInvokerInterceptor();
}
protected Object configuredProxy(SimpleRemoteSlsbInvokerInterceptor si, Class<?> ifc) throws NamingException {
si.afterPropertiesSet();
ProxyFactory pf = new ProxyFactory(new Class<?>[] {ifc});
pf.addAdvice(si);
return pf.getProxy();
}
@Test
public void testPerformsLookup() throws Exception {
RemoteInterface ejb = mock(RemoteInterface.class);
String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
configuredProxy(si, RemoteInterface.class);
verify(mockContext).close();
}
@Test
public void testPerformsLookupWithAccessContext() throws Exception {
RemoteInterface ejb = mock(RemoteInterface.class);
String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
si.setExposeAccessContext(true);
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
assertThat(target.targetMethod()).isNull();
verify(mockContext, times(2)).close();
verify(ejb).targetMethod();
}
@Test
public void testLookupFailure() throws Exception {
final NamingException nex = new NamingException();
final String jndiName = "foobar";
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) throws NamingException {
assertThat(jndiName.equals(name)).isTrue();
throw nex;
}
};
SimpleRemoteSlsbInvokerInterceptor si = new SimpleRemoteSlsbInvokerInterceptor();
si.setJndiName("foobar");
// default resourceRef=false should cause this to fail, as java:/comp/env will not
// automatically be added
si.setJndiTemplate(jt);
assertThatExceptionOfType(NamingException.class)
.isThrownBy(si::afterPropertiesSet)
.isSameAs(nex);
}
@Test
public void testInvokesMethodOnEjbInstance() throws Exception {
doTestInvokesMethodOnEjbInstance(true, true);
}
@Test
public void testInvokesMethodOnEjbInstanceWithLazyLookup() throws Exception {
doTestInvokesMethodOnEjbInstance(false, true);
}
@Test
public void testInvokesMethodOnEjbInstanceWithLazyLookupAndNoCache() throws Exception {
doTestInvokesMethodOnEjbInstance(false, false);
}
@Test
public void testInvokesMethodOnEjbInstanceWithNoCache() throws Exception {
doTestInvokesMethodOnEjbInstance(true, false);
}
private void doTestInvokesMethodOnEjbInstance(boolean lookupHomeOnStartup, boolean cacheHome) throws Exception {
Object retVal = new Object();
final RemoteInterface ejb = mock(RemoteInterface.class);
given(ejb.targetMethod()).willReturn(retVal);
int lookupCount = 1;
if (!cacheHome) {
lookupCount++;
if (lookupHomeOnStartup) {
lookupCount++;
}
}
final String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
si.setLookupHomeOnStartup(lookupHomeOnStartup);
si.setCacheHome(cacheHome);
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
assertThat(target.targetMethod() == retVal).isTrue();
assertThat(target.targetMethod() == retVal).isTrue();
verify(mockContext, times(lookupCount)).close();
verify(ejb, times(2)).remove();
}
@Test
public void testInvokesMethodOnEjbInstanceWithRemoteException() throws Exception {
final RemoteInterface ejb = mock(RemoteInterface.class);
given(ejb.targetMethod()).willThrow(new RemoteException());
ejb.remove();
final String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
assertThatExceptionOfType(RemoteException.class).isThrownBy(
target::targetMethod);
verify(mockContext).close();
verify(ejb, times(2)).remove();
}
@Test
public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh() throws Exception {
doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(true, true);
}
@Test
public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefreshAndLazyLookup() throws Exception {
doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(false, true);
}
@Test
public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefreshAndLazyLookupAndNoCache() throws Exception {
doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(false, false);
}
@Test
public void testInvokesMethodOnEjbInstanceWithConnectExceptionWithRefreshAndNoCache() throws Exception {
doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(true, false);
}
private void doTestInvokesMethodOnEjbInstanceWithConnectExceptionWithRefresh(
boolean lookupHomeOnStartup, boolean cacheHome) throws Exception {
final RemoteInterface ejb = mock(RemoteInterface.class);
given(ejb.targetMethod()).willThrow(new ConnectException(""));
int lookupCount = 2;
if (!cacheHome) {
lookupCount++;
if (lookupHomeOnStartup) {
lookupCount++;
}
}
final String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
si.setRefreshHomeOnConnectFailure(true);
si.setLookupHomeOnStartup(lookupHomeOnStartup);
si.setCacheHome(cacheHome);
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
assertThatExceptionOfType(ConnectException.class).isThrownBy(
target::targetMethod);
verify(mockContext, times(lookupCount)).close();
verify(ejb, times(2)).remove();
}
@Test
public void testInvokesMethodOnEjbInstanceWithBusinessInterface() throws Exception {
Object retVal = new Object();
final RemoteInterface ejb = mock(RemoteInterface.class);
given(ejb.targetMethod()).willReturn(retVal);
final String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
BusinessInterface target = (BusinessInterface) configuredProxy(si, BusinessInterface.class);
assertThat(target.targetMethod() == retVal).isTrue();
verify(mockContext).close();
verify(ejb).remove();
}
@Test
public void testInvokesMethodOnEjbInstanceWithBusinessInterfaceWithRemoteException() throws Exception {
final RemoteInterface ejb = mock(RemoteInterface.class);
given(ejb.targetMethod()).willThrow(new RemoteException());
final String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
BusinessInterface target = (BusinessInterface) configuredProxy(si, BusinessInterface.class);
assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(
target::targetMethod);
verify(mockContext).close();
verify(ejb).remove();
}
@Test
public void testApplicationException() throws Exception {
doTestException(new ApplicationException());
}
@Test
public void testRemoteException() throws Exception {
doTestException(new RemoteException());
}
private void doTestException(Exception expected) throws Exception {
final RemoteInterface ejb = mock(RemoteInterface.class);
given(ejb.targetMethod()).willThrow(expected);
final String jndiName= "foobar";
Context mockContext = mockContext(jndiName, ejb);
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
assertThatExceptionOfType(Exception.class)
.isThrownBy(target::targetMethod)
.isSameAs(expected);
verify(mockContext).close();
verify(ejb).remove();
}
/**
* Needed so that we can mock create() method.
*/
protected interface SlsbHome extends EJBHome {
EJBObject create() throws RemoteException, CreateException;
}
protected interface RemoteInterface extends EJBObject {
// Also business exception!?
Object targetMethod() throws RemoteException, ApplicationException;
}
protected interface BusinessInterface {
Object targetMethod() throws ApplicationException;
}
@SuppressWarnings("serial")
protected class ApplicationException extends Exception {
public ApplicationException() {
super("appException");
}
}
}

View File

@@ -1,288 +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.ejb.access;
import java.lang.reflect.Proxy;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.naming.NamingException;
import org.junit.jupiter.api.Test;
import org.springframework.jndi.JndiTemplate;
import org.springframework.remoting.RemoteAccessException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @since 21.05.2003
*/
public class SimpleRemoteStatelessSessionProxyFactoryBeanTests extends SimpleRemoteSlsbInvokerInterceptorTests {
@Override
protected SimpleRemoteSlsbInvokerInterceptor createInterceptor() {
return new SimpleRemoteStatelessSessionProxyFactoryBean();
}
@Override
protected Object configuredProxy(SimpleRemoteSlsbInvokerInterceptor si, Class<?> ifc) throws NamingException {
SimpleRemoteStatelessSessionProxyFactoryBean fb = (SimpleRemoteStatelessSessionProxyFactoryBean) si;
fb.setBusinessInterface(ifc);
fb.afterPropertiesSet();
return fb.getObject();
}
@Test
public void testInvokesMethod() throws Exception {
final int value = 11;
final String jndiName = "foo";
MyEjb myEjb = mock(MyEjb.class);
given(myEjb.getValue()).willReturn(value);
final MyHome home = mock(MyHome.class);
given(home.create()).willReturn(myEjb);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) {
// parameterize
assertThat(name.equals("java:comp/env/" + jndiName)).isTrue();
return home;
}
};
SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
fb.setResourceRef(true);
fb.setBusinessInterface(MyBusinessMethods.class);
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThat(mbm.getValue()).as("Returns expected value").isEqualTo(value);
verify(myEjb).remove();
}
@Test
public void testInvokesMethodOnEjb3StyleBean() throws Exception {
final int value = 11;
final String jndiName = "foo";
final MyEjb myEjb = mock(MyEjb.class);
given(myEjb.getValue()).willReturn(value);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) {
// parameterize
assertThat(name.equals("java:comp/env/" + jndiName)).isTrue();
return myEjb;
}
};
SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
fb.setResourceRef(true);
fb.setBusinessInterface(MyBusinessMethods.class);
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThat(mbm.getValue()).as("Returns expected value").isEqualTo(value);
}
@Override
@Test
public void testRemoteException() throws Exception {
final RemoteException rex = new RemoteException();
final String jndiName = "foo";
MyEjb myEjb = mock(MyEjb.class);
given(myEjb.getValue()).willThrow(rex);
// TODO might want to control this behaviour...
// Do we really want to call remove after a remote exception?
final MyHome home = mock(MyHome.class);
given(home.create()).willReturn(myEjb);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) {
// parameterize
assertThat(name.equals("java:comp/env/" + jndiName)).isTrue();
return home;
}
};
SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
fb.setResourceRef(true);
fb.setBusinessInterface(MyBusinessMethods.class);
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThatExceptionOfType(RemoteException.class)
.isThrownBy(mbm::getValue)
.isSameAs(rex);
verify(myEjb).remove();
}
@Test
public void testCreateException() throws Exception {
final String jndiName = "foo";
final CreateException cex = new CreateException();
final MyHome home = mock(MyHome.class);
given(home.create()).willThrow(cex);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) {
// parameterize
assertThat(name.equals(jndiName)).isTrue();
return home;
}
};
SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
// rely on default setting of resourceRef=false, no auto addition of java:/comp/env prefix
fb.setBusinessInterface(MyBusinessMethods.class);
assertThat(MyBusinessMethods.class).isEqualTo(fb.getBusinessInterface());
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyBusinessMethods mbm = (MyBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThatExceptionOfType(RemoteException.class).isThrownBy(mbm::getValue);
}
@Test
public void testCreateExceptionWithLocalBusinessInterface() throws Exception {
final String jndiName = "foo";
final CreateException cex = new CreateException();
final MyHome home = mock(MyHome.class);
given(home.create()).willThrow(cex);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) {
// parameterize
assertThat(name.equals(jndiName)).isTrue();
return home;
}
};
SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
// rely on default setting of resourceRef=false, no auto addition of java:/comp/env prefix
fb.setBusinessInterface(MyLocalBusinessMethods.class);
assertThat(MyLocalBusinessMethods.class).isEqualTo(fb.getBusinessInterface());
fb.setJndiTemplate(jt);
// Need lifecycle methods
fb.afterPropertiesSet();
MyLocalBusinessMethods mbm = (MyLocalBusinessMethods) fb.getObject();
assertThat(Proxy.isProxyClass(mbm.getClass())).isTrue();
assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(
mbm::getValue)
.withCause(cex);
}
@Test
public void testNoBusinessInterfaceSpecified() throws Exception {
// Will do JNDI lookup to get home but won't call create
// Could actually try to figure out interface from create?
final String jndiName = "foo";
final MyHome home = mock(MyHome.class);
JndiTemplate jt = new JndiTemplate() {
@Override
public Object lookup(String name) throws NamingException {
// parameterize
assertThat(name.equals(jndiName)).isTrue();
return home;
}
};
SimpleRemoteStatelessSessionProxyFactoryBean fb = new SimpleRemoteStatelessSessionProxyFactoryBean();
fb.setJndiName(jndiName);
// rely on default setting of resourceRef=false, no auto addition of java:/comp/env prefix
// Don't set business interface
fb.setJndiTemplate(jt);
// Check it's a singleton
assertThat(fb.isSingleton()).isTrue();
assertThatIllegalArgumentException().isThrownBy(
fb::afterPropertiesSet)
.withMessageContaining("businessInterface");
// Expect no methods on home
verifyNoInteractions(home);
}
protected interface MyHome extends EJBHome {
MyBusinessMethods create() throws CreateException, RemoteException;
}
protected interface MyBusinessMethods {
int getValue() throws RemoteException;
}
protected interface MyLocalBusinessMethods {
int getValue();
}
protected interface MyEjb extends EJBObject, MyBusinessMethods {
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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,20 +35,21 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class JeeNamespaceHandlerEventTests {
private CollectingReaderEventListener eventListener = new CollectingReaderEventListener();
private final CollectingReaderEventListener eventListener = new CollectingReaderEventListener();
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
private XmlBeanDefinitionReader reader;
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@BeforeEach
public void setUp() throws Exception {
public void setup() throws Exception {
this.reader = new XmlBeanDefinitionReader(this.beanFactory);
this.reader.setEventListener(this.eventListener);
this.reader.loadBeanDefinitions(new ClassPathResource("jeeNamespaceHandlerTests.xml", getClass()));
}
@Test
public void testJndiLookupComponentEventReceived() {
ComponentDefinition component = this.eventListener.getComponentDefinition("simple");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,6 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.testfixture.beans.ITestBean;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean;
import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean;
import org.springframework.jndi.JndiObjectFactoryBean;
import static org.assertj.core.api.Assertions.assertThat;
@@ -93,46 +91,17 @@ public class JeeNamespaceHandlerTests {
@Test
public void testSimpleLocalSlsb() {
BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("simpleLocalEjb");
assertThat(beanDefinition.getBeanClassName()).isEqualTo(LocalStatelessSessionProxyFactoryBean.class.getName());
assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName());
assertThat(beanDefinition.getBeanClassName()).isEqualTo(JndiObjectFactoryBean.class.getName());
assertPropertyValue(beanDefinition, "jndiName", "ejb/MyLocalBean");
}
@Test
public void testSimpleRemoteSlsb() {
BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("simpleRemoteEjb");
assertThat(beanDefinition.getBeanClassName()).isEqualTo(SimpleRemoteStatelessSessionProxyFactoryBean.class.getName());
assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName());
assertThat(beanDefinition.getBeanClassName()).isEqualTo(JndiObjectFactoryBean.class.getName());
assertPropertyValue(beanDefinition, "jndiName", "ejb/MyRemoteBean");
}
@Test
public void testComplexLocalSlsb() {
BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("complexLocalEjb");
assertThat(beanDefinition.getBeanClassName()).isEqualTo(LocalStatelessSessionProxyFactoryBean.class.getName());
assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName());
assertPropertyValue(beanDefinition, "jndiName", "ejb/MyLocalBean");
assertPropertyValue(beanDefinition, "cacheHome", "true");
assertPropertyValue(beanDefinition, "lookupHomeOnStartup", "true");
assertPropertyValue(beanDefinition, "resourceRef", "true");
assertPropertyValue(beanDefinition, "jndiEnvironment", "foo=bar");
}
@Test
public void testComplexRemoteSlsb() {
BeanDefinition beanDefinition = this.beanFactory.getMergedBeanDefinition("complexRemoteEjb");
assertThat(beanDefinition.getBeanClassName()).isEqualTo(SimpleRemoteStatelessSessionProxyFactoryBean.class.getName());
assertPropertyValue(beanDefinition, "businessInterface", ITestBean.class.getName());
assertPropertyValue(beanDefinition, "jndiName", "ejb/MyRemoteBean");
assertPropertyValue(beanDefinition, "cacheHome", "true");
assertPropertyValue(beanDefinition, "lookupHomeOnStartup", "true");
assertPropertyValue(beanDefinition, "resourceRef", "true");
assertPropertyValue(beanDefinition, "jndiEnvironment", "foo=bar");
assertPropertyValue(beanDefinition, "homeInterface", "org.springframework.beans.testfixture.beans.ITestBean");
assertPropertyValue(beanDefinition, "refreshHomeOnConnectFailure", "true");
assertPropertyValue(beanDefinition, "cacheSessionBean", "true");
}
@Test
public void testLazyInitJndiLookup() {
BeanDefinition definition = this.beanFactory.getMergedBeanDefinition("lazyDataSource");

View File

@@ -16,10 +16,9 @@
package org.springframework.validation.beanvalidation;
import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import jakarta.annotation.PostConstruct;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
@@ -99,7 +98,7 @@ public class BeanValidationPostProcessorTests {
bd.getPropertyValues().add("stringValue", "s");
ac.registerBeanDefinition("bean", bd);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> ac.refresh())
.isThrownBy(ac::refresh)
.havingRootCause()
.withMessageContainingAll("stringValue", "invalid");
ac.close();

View File

@@ -19,12 +19,11 @@ package org.springframework.validation.beanvalidation;
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 jakarta.validation.ValidationException;
import jakarta.validation.Validator;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.groups.Default;
import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory;
@@ -49,15 +48,17 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
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<?>) proxyFactory.getProxy());
doTestProxyValidation((MyValidInterface<String>) proxyFactory.getProxy());
}
@Test
@SuppressWarnings("unchecked")
public void testMethodValidationPostProcessor() {
StaticApplicationContext ac = new StaticApplicationContext();
ac.registerSingleton("mvpp", MethodValidationPostProcessor.class);
@@ -70,8 +71,7 @@ public class MethodValidationTests {
ac.close();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void doTestProxyValidation(MyValidInterface proxy) {
private void doTestProxyValidation(MyValidInterface<String> proxy) {
assertThat(proxy.myValidMethod("value", 5)).isNotNull();
assertThatExceptionOfType(ValidationException.class).isThrownBy(() ->
proxy.myValidMethod("value", 15));
@@ -90,8 +90,8 @@ public class MethodValidationTests {
}
@Test
@SuppressWarnings("resource")
public void testLazyValidatorForMethodValidation() {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfig.class, CustomValidatorBean.class,
MyValidBean.class, MyValidFactoryBean.class);
@@ -99,8 +99,8 @@ public class MethodValidationTests {
}
@Test
@SuppressWarnings("resource")
public void testLazyValidatorForMethodValidationWithProxyTargetClass() {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LazyMethodValidationConfigWithProxyTargetClass.class, CustomValidatorBean.class,
MyValidBean.class, MyValidFactoryBean.class);

View File

@@ -26,23 +26,24 @@ 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 jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Payload;
import jakarta.validation.Valid;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -228,6 +229,48 @@ public class SpringValidatorAdapterTests {
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")
@@ -485,4 +528,34 @@ public class SpringValidatorAdapterTests {
}
}
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

@@ -28,16 +28,15 @@ 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 jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Payload;
import jakarta.validation.Valid;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import jakarta.validation.constraints.NotNull;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorFactory;
import org.junit.jupiter.api.Test;