From fd53d2a51a4de263ac18d2f698abeab7afabce75 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 8 Jun 2017 22:52:57 +0200 Subject: [PATCH] Consistent use of @Nullable in spring-test This commit also removes nullability from two common spots: ResolvableType.getType() and TargetSource.getTarget(), both of which are never effectively null with any regular implementation. For such scenarios, a non-null empty type/target is the cleaner contract. Issue: SPR-15540 --- .../org/springframework/aop/TargetSource.java | 3 - .../aop/framework/CglibAopProxy.java | 40 ++--- .../aop/framework/JdkDynamicAopProxy.java | 7 +- .../framework/ReflectiveMethodInvocation.java | 4 +- .../springframework/aop/support/AopUtils.java | 2 +- .../aop/target/EmptyTargetSource.java | 20 +-- .../aspectj/AbstractTransactionAspect.aj | 7 +- .../factory/wiring/BeanConfigurerSupport.java | 15 +- .../ComponentScanAnnotationParser.java | 6 +- .../org/springframework/jmx/IJmxTestBean.java | 16 +- .../remoting/rmi/RmiSupportTests.java | 17 +-- .../springframework/core/ResolvableType.java | 29 ++-- .../core/SerializableTypeWrapper.java | 15 +- .../annotation/AnnotatedElementUtils.java | 4 +- .../core/annotation/AnnotationUtils.java | 10 +- .../core/style/DefaultToStringStyler.java | 7 +- .../core/style/ToStringCreator.java | 2 +- .../core/style/ToStringStyler.java | 6 +- .../springframework/util/CollectionUtils.java | 14 +- .../util/LinkedMultiValueMap.java | 14 +- .../springframework/util/MultiValueMap.java | 4 +- .../springframework/util/ReflectionUtils.java | 2 +- .../core/ResolvableTypeTests.java | 3 +- .../invocation/InvocableHandlerMethod.java | 5 +- .../messaging/simp/stomp/StompHeaders.java | 2 +- .../http/client/MockClientHttpResponse.java | 7 +- .../reactive/MockServerHttpRequest.java | 2 +- .../mock/jndi/SimpleNamingContext.java | 7 +- .../mock/jndi/SimpleNamingContextBuilder.java | 5 +- .../mock/web/HeaderValueHolder.java | 2 + .../mock/web/MockAsyncContext.java | 2 +- .../mock/web/MockBodyContent.java | 6 +- .../mock/web/MockFilterConfig.java | 5 +- .../mock/web/MockHttpServletRequest.java | 38 +++-- .../mock/web/MockHttpServletResponse.java | 13 +- .../mock/web/MockHttpSession.java | 7 +- .../mock/web/MockJspWriter.java | 4 +- .../mock/web/MockMultipartFile.java | 12 +- .../mock/web/MockPageContext.java | 25 ++- .../springframework/mock/web/MockPart.java | 12 +- .../mock/web/MockServletConfig.java | 5 +- .../mock/web/MockServletContext.java | 13 +- .../function/server/MockServerRequest.java | 13 +- .../test/annotation/ProfileValueUtils.java | 3 +- .../test/context/ContextConfiguration.java | 4 +- .../ContextConfigurationAttributes.java | 35 +++-- .../test/context/ContextLoader.java | 4 +- .../context/MergedContextConfiguration.java | 143 +++++++++--------- .../test/context/TestContext.java | 16 +- .../test/context/TestContextManager.java | 6 +- .../context/cache/DefaultContextCache.java | 12 +- ...AbstractExpressionEvaluatingCondition.java | 15 +- .../junit/jupiter/SpringExtension.java | 2 + .../junit/jupiter/SpringJUnitConfig.java | 2 +- .../jupiter/web/SpringJUnitWebConfig.java | 2 +- ...TransactionalJUnit4SpringContextTests.java | 7 +- .../junit4/SpringJUnit4ClassRunner.java | 9 +- .../junit4/rules/SpringMethodRule.java | 7 +- .../support/AbstractContextLoader.java | 8 +- .../AbstractTestContextBootstrapper.java | 4 +- .../context/support/ActiveProfilesUtils.java | 13 +- .../AnnotationConfigContextLoader.java | 5 +- .../AnnotationConfigContextLoaderUtils.java | 5 +- .../ApplicationContextInitializerUtils.java | 4 +- .../context/support/ContextLoaderUtils.java | 10 +- .../context/support/DefaultTestContext.java | 13 +- ...endencyInjectionTestExecutionListener.java | 2 +- .../support/TestPropertySourceAttributes.java | 31 ++-- .../support/TestPropertySourceUtils.java | 7 +- ...TransactionalTestNGSpringContextTests.java | 7 +- .../transaction/TransactionContext.java | 15 +- .../transaction/TransactionContextHolder.java | 17 ++- .../TransactionalTestExecutionListener.java | 10 +- .../util/TestContextResourceUtils.java | 13 +- .../web/AnnotationConfigWebContextLoader.java | 5 +- .../web/WebMergedContextConfiguration.java | 6 +- .../MockServerContainerContextCustomizer.java | 12 +- .../test/jdbc/JdbcTestUtils.java | 14 +- .../test/util/AssertionErrors.java | 9 +- .../test/util/JsonExpectationsHelper.java | 16 +- .../test/util/JsonPathExpectationsHelper.java | 9 +- .../test/util/MetaAnnotationUtils.java | 9 +- .../test/util/ReflectionTestUtils.java | 30 ++-- .../test/util/XpathExpectationsHelper.java | 36 +++-- .../test/web/ModelAndViewAssert.java | 85 +++++------ .../client/match/ContentRequestMatchers.java | 8 +- .../client/match/MockRestRequestMatchers.java | 11 +- .../server/DefaultRouterFunctionSpec.java | 4 +- .../reactive/server/DefaultWebTestClient.java | 56 +++---- .../reactive/server/EntityExchangeResult.java | 5 +- .../web/reactive/server/ExchangeResult.java | 10 +- .../web/reactive/server/HeaderAssertions.java | 10 +- .../reactive/server/JsonPathAssertions.java | 2 +- .../test/web/servlet/DefaultMvcResult.java | 9 +- .../test/web/servlet/MockMvc.java | 24 +-- .../web/servlet/MockMvcBuilderSupport.java | 11 +- .../test/web/servlet/MvcResult.java | 6 +- .../test/web/servlet/RequestBuilder.java | 3 +- .../htmlunit/HtmlUnitRequestBuilder.java | 25 +-- .../htmlunit/MockMvcWebConnection.java | 3 - .../MockHttpServletRequestBuilder.java | 22 ++- .../servlet/result/ContentResultMatchers.java | 12 +- .../servlet/result/CookieResultMatchers.java | 5 +- .../servlet/result/HandlerResultMatchers.java | 14 +- .../servlet/result/HeaderResultMatchers.java | 5 +- .../servlet/result/MockMvcResultHandlers.java | 5 +- .../servlet/result/MockMvcResultMatchers.java | 10 +- .../servlet/result/ModelResultMatchers.java | 27 ++-- .../servlet/result/PrintingResultHandler.java | 9 +- .../servlet/result/RequestResultMatchers.java | 13 +- .../servlet/result/ViewResultMatchers.java | 8 +- .../servlet/result/XpathResultMatchers.java | 4 +- .../servlet/setup/AbstractMockMvcBuilder.java | 4 +- .../setup/ConfigurableMockMvcBuilder.java | 19 +-- .../servlet/setup/DefaultMockMvcBuilder.java | 5 +- .../web/servlet/setup/MockMvcConfigurer.java | 12 +- .../setup/StandaloneMockMvcBuilder.java | 23 ++- .../mock/web/MockHttpServletRequestTests.java | 6 - .../MergedContextConfigurationTests.java | 16 +- ...bstractContextConfigurationUtilsTests.java | 6 +- .../support/ActiveProfilesUtilsTests.java | 5 +- ...strapTestUtilsContextInitializerTests.java | 4 +- .../htmlunit/MockMvcWebConnectionTests.java | 19 +-- .../jca/cci/object/SimpleRecordOperation.java | 4 +- .../interceptor/TransactionInterceptor.java | 9 +- .../org/springframework/http/HttpHeaders.java | 2 +- .../client/reactive/ClientHttpResponse.java | 4 +- .../http/codec/json/Jackson2JsonEncoder.java | 10 +- .../context/request/RequestContextHolder.java | 2 +- .../result/view/UrlBasedViewResolver.java | 10 +- .../result/view/ViewResolverSupport.java | 1 + .../servlet/handler/MappedInterceptor.java | 3 +- ...stractMessageConverterMethodProcessor.java | 1 - .../servlet/view/UrlBasedViewResolver.java | 9 +- 134 files changed, 812 insertions(+), 777 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/TargetSource.java b/spring-aop/src/main/java/org/springframework/aop/TargetSource.java index 67f5a4dba3..888030533d 100644 --- a/spring-aop/src/main/java/org/springframework/aop/TargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/TargetSource.java @@ -16,8 +16,6 @@ package org.springframework.aop; -import org.springframework.lang.Nullable; - /** * A {@code TargetSource} is used to obtain the current "target" of * an AOP invocation, which will be invoked via reflection if no around @@ -59,7 +57,6 @@ public interface TargetSource extends TargetClassAware { * @return the target object, which contains the joinpoint * @throws Exception if the target object can't be resolved */ - @Nullable Object getTarget() throws Exception; /** diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java index f1e5f4e32e..3c619f8982 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java @@ -326,8 +326,12 @@ class CglibAopProxy implements AopProxy, Serializable { // TODO: small memory optimization here (can skip creation for methods with no advice) for (int x = 0; x < methods.length; x++) { List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass); - fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( - chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); + Object target = this.advised.getTargetSource().getTarget(); + Class targetClass = this.advised.getTargetClass(); + if (targetClass == null) { + targetClass = target.getClass(); + } + fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(chain, target, targetClass); this.fixedInterceptorMap.put(methods[x].toString(), x); } @@ -374,7 +378,7 @@ class CglibAopProxy implements AopProxy, Serializable { * {@code proxy} and also verifies that {@code null} is not returned as a primitive. */ @Nullable - private static Object processReturnType(Object proxy, @Nullable Object target, Method method, @Nullable Object retVal) { + private static Object processReturnType(Object proxy, Object target, Method method, @Nullable Object retVal) { // Massage return value if necessary if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { @@ -409,7 +413,7 @@ class CglibAopProxy implements AopProxy, Serializable { private final Object target; - public StaticUnadvisedInterceptor(@Nullable Object target) { + public StaticUnadvisedInterceptor(Object target) { this.target = target; } @@ -430,7 +434,7 @@ class CglibAopProxy implements AopProxy, Serializable { private final Object target; - public StaticUnadvisedExposedInterceptor(@Nullable Object target) { + public StaticUnadvisedExposedInterceptor(Object target) { this.target = target; } @@ -472,9 +476,7 @@ class CglibAopProxy implements AopProxy, Serializable { return processReturnType(proxy, target, method, retVal); } finally { - if (target != null) { - this.targetSource.releaseTarget(target); - } + this.targetSource.releaseTarget(target); } } } @@ -503,9 +505,7 @@ class CglibAopProxy implements AopProxy, Serializable { } finally { AopContext.setCurrentProxy(oldProxy); - if (target != null) { - this.targetSource.releaseTarget(target); - } + this.targetSource.releaseTarget(target); } } } @@ -612,9 +612,7 @@ class CglibAopProxy implements AopProxy, Serializable { private final Class targetClass; - public FixedChainStaticTargetInterceptor( - List adviceChain, @Nullable Object target, @Nullable Class targetClass) { - + public FixedChainStaticTargetInterceptor(List adviceChain, Object target, Class targetClass) { this.adviceChain = adviceChain; this.target = target; this.targetClass = targetClass; @@ -650,7 +648,6 @@ class CglibAopProxy implements AopProxy, Serializable { public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; - Class targetClass = null; Object target = null; try { if (this.advised.exposeProxy) { @@ -658,12 +655,9 @@ class CglibAopProxy implements AopProxy, Serializable { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } - // May be null. Get as late as possible to minimize the time we - // "own" the target, in case it comes from a pool... + // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool... target = getTarget(); - if (target != null) { - targetClass = target.getClass(); - } + Class targetClass = target.getClass(); List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, @@ -709,7 +703,6 @@ class CglibAopProxy implements AopProxy, Serializable { return this.advised.hashCode(); } - @Nullable protected Object getTarget() throws Exception { return this.advised.getTargetSource().getTarget(); } @@ -729,9 +722,8 @@ class CglibAopProxy implements AopProxy, Serializable { private final boolean publicMethod; - public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method, - Object[] arguments, @Nullable Class targetClass, - List interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { + public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, + Class targetClass, List interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); this.methodProxy = methodProxy; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java index 92357a5231..a88d8caed8 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java @@ -159,7 +159,6 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; - Class targetClass = null; Object target = null; try { @@ -189,12 +188,10 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa setProxyContext = true; } - // May be null. Get as late as possible to minimize the time we "own" the target, + // Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); - if (target != null) { - targetClass = target.getClass(); - } + Class targetClass = target.getClass(); // Get the interception chain for this method. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java b/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java index 664786fea8..19a07aaac7 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java @@ -103,8 +103,8 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea * but would complicate the code. And it would work only for static pointcuts. */ protected ReflectiveMethodInvocation( - Object proxy, @Nullable Object target, Method method, Object[] arguments, - @Nullable Class targetClass, List interceptorsAndDynamicMethodMatchers) { + Object proxy, Object target, Method method, Object[] arguments, + Class targetClass, List interceptorsAndDynamicMethodMatchers) { this.proxy = proxy; this.target = target; diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java b/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java index 59ed97481a..115fa92679 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java @@ -329,7 +329,7 @@ public abstract class AopUtils { * @throws org.springframework.aop.AopInvocationException in case of a reflection error */ @Nullable - public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) + public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable { // Use reflection to invoke the method. diff --git a/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java index 9f4936cb12..91535d4bfe 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,13 @@ import org.springframework.util.ObjectUtils; */ public class EmptyTargetSource implements TargetSource, Serializable { + /** + * The canonical (Singleton) instance of this {@link EmptyTargetSource}. + */ + public static final EmptyTargetSource INSTANCE = new EmptyTargetSource(null, true); + + private static final Object EMPTY_TARGET = new Object(); + /** use serialVersionUID from Spring 1.2 for interoperability */ private static final long serialVersionUID = 3680494563553489691L; @@ -40,12 +47,6 @@ public class EmptyTargetSource implements TargetSource, Serializable { // Static factory methods //--------------------------------------------------------------------- - /** - * The canonical (Singleton) instance of this {@link EmptyTargetSource}. - */ - public static final EmptyTargetSource INSTANCE = new EmptyTargetSource(null, true); - - /** * Return an EmptyTargetSource for the given target Class. * @param targetClass the target Class (may be {@code null}) @@ -87,6 +88,7 @@ public class EmptyTargetSource implements TargetSource, Serializable { this.isStatic = isStatic; } + /** * Always returns the specified target Class, or {@code null} if none. */ @@ -104,11 +106,11 @@ public class EmptyTargetSource implements TargetSource, Serializable { } /** - * Always returns {@code null}. + * Always returns {@code DUMMY_TARGET}. */ @Override public Object getTarget() { - return null; + return EMPTY_TARGET; } /** diff --git a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj index 49a197495e..17204f9310 100644 --- a/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj +++ b/spring-aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,12 +73,9 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor } }); } - catch (RuntimeException ex) { + catch (RuntimeException | Error ex) { throw ex; } - catch (Error err) { - throw err; - } catch (Throwable thr) { Rethrower.rethrow(thr); throw new IllegalStateException("Should never get here", thr); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java index 961fb47987..2e296e27ec 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanConfigurerSupport.java @@ -141,13 +141,11 @@ public class BeanConfigurerSupport implements BeanFactoryAware, InitializingBean !this.beanFactory.containsBean(bwi.getBeanName()))) { // Perform autowiring (also applying standard factory / post-processor callbacks). this.beanFactory.autowireBeanProperties(beanInstance, bwi.getAutowireMode(), bwi.getDependencyCheck()); - Object result = this.beanFactory.initializeBean(beanInstance, bwi.getBeanName()); - checkExposedObject(result, beanInstance); + this.beanFactory.initializeBean(beanInstance, bwi.getBeanName()); } else { // Perform explicit wiring based on the specified bean definition. - Object result = this.beanFactory.configureBean(beanInstance, bwi.getBeanName()); - checkExposedObject(result, beanInstance); + this.beanFactory.configureBean(beanInstance, bwi.getBeanName()); } } catch (BeanCreationException ex) { @@ -168,13 +166,4 @@ public class BeanConfigurerSupport implements BeanFactoryAware, InitializingBean } } - private void checkExposedObject(@Nullable Object exposedObject, Object originalBeanInstance) { - if (exposedObject != originalBeanInstance) { - throw new IllegalStateException("Post-processor tried to replace bean instance of type [" + - originalBeanInstance.getClass().getName() + "] with (proxy) object of type [" + - (exposedObject != null ? exposedObject.getClass().getName() : null) + - "] - not supported for aspect-configured classes!"); - } - } - } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java index 75273b0a5b..48c9e48ab9 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java @@ -38,7 +38,6 @@ import org.springframework.core.type.filter.AspectJTypeFilter; import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.RegexPatternTypeFilter; import org.springframework.core.type.filter.TypeFilter; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -64,7 +63,7 @@ class ComponentScanAnnotationParser { private final BeanDefinitionRegistry registry; - public ComponentScanAnnotationParser(@Nullable Environment environment, @Nullable ResourceLoader resourceLoader, + public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader, BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) { this.environment = environment; @@ -75,9 +74,6 @@ class ComponentScanAnnotationParser { public Set parse(AnnotationAttributes componentScan, final String declaringClass) { - Assert.state(this.environment != null, "Environment must not be null"); - Assert.state(this.resourceLoader != null, "ResourceLoader must not be null"); - ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); diff --git a/spring-context/src/test/java/org/springframework/jmx/IJmxTestBean.java b/spring-context/src/test/java/org/springframework/jmx/IJmxTestBean.java index ca6a1cd796..185d5fcd7a 100644 --- a/spring-context/src/test/java/org/springframework/jmx/IJmxTestBean.java +++ b/spring-context/src/test/java/org/springframework/jmx/IJmxTestBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,19 +22,19 @@ package org.springframework.jmx; */ public interface IJmxTestBean { - public int add(int x, int y); + int add(int x, int y); - public long myOperation(); + long myOperation(); - public int getAge(); + int getAge(); - public void setAge(int age); + void setAge(int age); - public void setName(String name) throws Exception; + void setName(String name) throws Exception; - public String getName(); + String getName(); // used to test invalid methods that exist in the proxy interface - public void dontExposeMe(); + void dontExposeMe(); } diff --git a/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java b/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java index a3aba60d4e..2317a114b9 100644 --- a/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java +++ b/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -449,24 +449,21 @@ public class RmiSupportTests { } - public static interface IBusinessBean { - - public void setName(String name); + public interface IBusinessBean { + void setName(String name); } - public static interface IWrongBusinessBean { - - public void setOtherName(String name); + public interface IWrongBusinessBean { + void setOtherName(String name); } - public static interface IRemoteBean extends Remote { - - public void setName(String name) throws RemoteException; + public interface IRemoteBean extends Remote { + void setName(String name) throws RemoteException; } diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java index 6a85923a92..2201b8ffb6 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -86,7 +86,7 @@ public class ResolvableType implements Serializable { * {@code ResolvableType} returned when no value is available. {@code NONE} is used * in preference to {@code null} so that multiple method calls can be safely chained. */ - public static final ResolvableType NONE = new ResolvableType(null, null, null, 0); + public static final ResolvableType NONE = new ResolvableType(EmptyType.INSTANCE, null, null, 0); private static final ResolvableType[] EMPTY_TYPES_ARRAY = new ResolvableType[0]; @@ -95,7 +95,7 @@ public class ResolvableType implements Serializable { /** - * The underlying Java type being managed (only ever {@code null} for {@link #NONE}). + * The underlying Java type being managed. */ private final Type type; @@ -146,7 +146,7 @@ public class ResolvableType implements Serializable { * with upfront resolution and a pre-calculated hash. * @since 4.2 */ - private ResolvableType(@Nullable Type type, @Nullable TypeProvider typeProvider, + private ResolvableType(Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver, Integer hash) { this.type = type; @@ -188,10 +188,8 @@ public class ResolvableType implements Serializable { /** - * Return the underling Java {@link Type} being managed. With the exception of - * the {@link #NONE} constant, this method will never return {@code null}. + * Return the underling Java {@link Type} being managed. */ - @Nullable public Type getType() { return SerializableTypeWrapper.unwrap(this.type); } @@ -761,7 +759,10 @@ public class ResolvableType implements Serializable { } private Class resolveClass() { - if (this.type instanceof Class || this.type == null) { + if (this.type == EmptyType.INSTANCE) { + return null; + } + if (this.type instanceof Class) { return (Class) this.type; } if (this.type instanceof GenericArrayType) { @@ -903,7 +904,7 @@ public class ResolvableType implements Serializable { * Custom serialization support for {@link #NONE}. */ private Object readResolve() { - return (this.type == null ? NONE : this); + return (this.type == EmptyType.INSTANCE ? NONE : this); } /** @@ -1567,7 +1568,6 @@ public class ResolvableType implements Serializable { resolveToWildcard = resolveToWildcard.resolveType(); } WildcardType wildcardType = (WildcardType) resolveToWildcard.type; - Assert.state(wildcardType != null, "Wildcard type not resolved"); Kind boundsType = (wildcardType.getLowerBounds().length > 0 ? Kind.LOWER : Kind.UPPER); Type[] bounds = boundsType == Kind.UPPER ? wildcardType.getUpperBounds() : wildcardType.getLowerBounds(); ResolvableType[] resolvableBounds = new ResolvableType[bounds.length]; @@ -1583,4 +1583,15 @@ public class ResolvableType implements Serializable { enum Kind {UPPER, LOWER} } + + @SuppressWarnings("serial") + static class EmptyType implements Type, Serializable { + + static final Type INSTANCE = new EmptyType(); + + Object readResolve() { + return INSTANCE; + } + } + } diff --git a/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java b/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java index bc0dfb2f79..82b87c085b 100644 --- a/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java +++ b/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java @@ -37,19 +37,19 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; /** - * Internal utility class that can be used to obtain wrapped {@link Serializable} variants - * of {@link java.lang.reflect.Type}s. + * Internal utility class that can be used to obtain wrapped {@link Serializable} + * variants of {@link java.lang.reflect.Type}s. * *

{@link #forField(Field) Fields} or {@link #forMethodParameter(MethodParameter) - * MethodParameters} can be used as the root source for a serializable type. Alternatively - * the {@link #forGenericSuperclass(Class) superclass}, + * MethodParameters} can be used as the root source for a serializable type. + * Alternatively the {@link #forGenericSuperclass(Class) superclass}, * {@link #forGenericInterfaces(Class) interfaces} or {@link #forTypeParameters(Class) * type parameters} or a regular {@link Class} can also be used as source. * *

The returned type will either be a {@link Class} or a serializable proxy of * {@link GenericArrayType}, {@link ParameterizedType}, {@link TypeVariable} or - * {@link WildcardType}. With the exception of {@link Class} (which is final) calls to - * methods that return further {@link Type}s (for example + * {@link WildcardType}. With the exception of {@link Class} (which is final) calls + * to methods that return further {@link Type}s (for example * {@link GenericArrayType#getGenericComponentType()}) will be automatically wrapped. * * @author Phillip Webb @@ -123,13 +123,12 @@ abstract class SerializableTypeWrapper { * @return the original non-serializable type */ @SuppressWarnings("unchecked") - @Nullable public static T unwrap(T type) { Type unwrapped = type; while (unwrapped instanceof SerializableTypeProxy) { unwrapped = ((SerializableTypeProxy) type).getTypeProvider().getType(); } - return (T) unwrapped; + return (unwrapped != null ? (T) unwrapped : type); } /** diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java index d673863300..c21879ad8d 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java @@ -423,7 +423,7 @@ public class AnnotatedElementUtils { // Exhaustive retrieval of merged annotation attributes... AnnotationAttributes attributes = getMergedAnnotationAttributes(element, annotationType); - return AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element); + return (attributes != null ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null); } /** @@ -726,7 +726,7 @@ public class AnnotatedElementUtils { // Exhaustive retrieval of merged annotation attributes... AnnotationAttributes attributes = findMergedAnnotationAttributes(element, annotationType, false, false); - return AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element); + return (attributes != null ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null); } /** diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index fce31c0e41..4d2d33279d 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -1482,8 +1482,7 @@ public abstract class AnnotationUtils { * @param annotationType the type of annotation to synthesize * @param annotatedElement the element that is annotated with the annotation * corresponding to the supplied attributes; may be {@code null} if unknown - * @return the synthesized annotation, or {@code null} if the supplied attributes - * map is {@code null} + * @return the synthesized annotation * @throws IllegalArgumentException if a required attribute is missing or if an * attribute is not of the correct type * @throws AnnotationConfigurationException if invalid configuration of @@ -1495,14 +1494,11 @@ public abstract class AnnotationUtils { * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean) */ @SuppressWarnings("unchecked") - @Nullable - public static A synthesizeAnnotation(@Nullable Map attributes, + public static A synthesizeAnnotation(Map attributes, Class annotationType, @Nullable AnnotatedElement annotatedElement) { + Assert.notNull(attributes, "'attributes' must not be null"); Assert.notNull(annotationType, "'annotationType' must not be null"); - if (attributes == null) { - return null; - } MapAnnotationAttributeExtractor attributeExtractor = new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement); diff --git a/spring-core/src/main/java/org/springframework/core/style/DefaultToStringStyler.java b/spring-core/src/main/java/org/springframework/core/style/DefaultToStringStyler.java index 97a6ce23ce..a6d23e448c 100644 --- a/spring-core/src/main/java/org/springframework/core/style/DefaultToStringStyler.java +++ b/spring-core/src/main/java/org/springframework/core/style/DefaultToStringStyler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.core.style; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -77,7 +78,7 @@ public class DefaultToStringStyler implements ToStringStyler { } @Override - public void styleField(StringBuilder buffer, String fieldName, Object value) { + public void styleField(StringBuilder buffer, String fieldName, @Nullable Object value) { styleFieldStart(buffer, fieldName); styleValue(buffer, value); styleFieldEnd(buffer, fieldName); @@ -91,7 +92,7 @@ public class DefaultToStringStyler implements ToStringStyler { } @Override - public void styleValue(StringBuilder buffer, Object value) { + public void styleValue(StringBuilder buffer, @Nullable Object value) { buffer.append(this.valueStyler.style(value)); } diff --git a/spring-core/src/main/java/org/springframework/core/style/ToStringCreator.java b/spring-core/src/main/java/org/springframework/core/style/ToStringCreator.java index 1e9ed044b9..5b5aac6790 100644 --- a/spring-core/src/main/java/org/springframework/core/style/ToStringCreator.java +++ b/spring-core/src/main/java/org/springframework/core/style/ToStringCreator.java @@ -152,7 +152,7 @@ public class ToStringCreator { * @param value the field value * @return this, to support call-chaining */ - public ToStringCreator append(String fieldName, Object value) { + public ToStringCreator append(String fieldName, @Nullable Object value) { printFieldSeparatorIfNecessary(); this.styler.styleField(this.buffer, fieldName, value); return this; diff --git a/spring-core/src/main/java/org/springframework/core/style/ToStringStyler.java b/spring-core/src/main/java/org/springframework/core/style/ToStringStyler.java index 9ae12df5f5..c341c611df 100644 --- a/spring-core/src/main/java/org/springframework/core/style/ToStringStyler.java +++ b/spring-core/src/main/java/org/springframework/core/style/ToStringStyler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package org.springframework.core.style; +import org.springframework.lang.Nullable; + /** * A strategy interface for pretty-printing {@code toString()} methods. * Encapsulates the print algorithms; some other object such as a builder @@ -46,7 +48,7 @@ public interface ToStringStyler { * @param fieldName the he name of the field * @param value the field value */ - void styleField(StringBuilder buffer, String fieldName, Object value); + void styleField(StringBuilder buffer, String fieldName, @Nullable Object value); /** * Style the given value. diff --git a/spring-core/src/main/java/org/springframework/util/CollectionUtils.java b/spring-core/src/main/java/org/springframework/util/CollectionUtils.java index 1d2c843192..46025e820e 100644 --- a/spring-core/src/main/java/org/springframework/util/CollectionUtils.java +++ b/spring-core/src/main/java/org/springframework/util/CollectionUtils.java @@ -404,6 +404,12 @@ public abstract class CollectionUtils { this.map = map; } + @Override + public V getFirst(K key) { + List values = this.map.get(key); + return (values != null ? values.get(0) : null); + } + @Override public void add(K key, @Nullable V value) { List values = this.map.computeIfAbsent(key, k -> new LinkedList<>()); @@ -411,17 +417,11 @@ public abstract class CollectionUtils { } @Override - public void addAll(K key, List values) { + public void addAll(K key, List values) { List currentValues = this.map.computeIfAbsent(key, k -> new LinkedList<>()); currentValues.addAll(values); } - @Override - public V getFirst(K key) { - List values = this.map.get(key); - return (values != null ? values.get(0) : null); - } - @Override public void set(K key, V value) { List values = new LinkedList<>(); diff --git a/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java b/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java index 92968c6884..5e2b7bc54f 100644 --- a/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java +++ b/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java @@ -75,6 +75,12 @@ public class LinkedMultiValueMap implements MultiValueMap, Serializa // MultiValueMap implementation + @Override + public V getFirst(K key) { + List values = this.targetMap.get(key); + return (values != null ? values.get(0) : null); + } + @Override public void add(K key, @Nullable V value) { List values = this.targetMap.computeIfAbsent(key, k -> new LinkedList<>()); @@ -82,17 +88,11 @@ public class LinkedMultiValueMap implements MultiValueMap, Serializa } @Override - public void addAll(K key, List values) { + public void addAll(K key, List values) { List currentValues = this.targetMap.computeIfAbsent(key, k -> new LinkedList<>()); currentValues.addAll(values); } - @Override - public V getFirst(K key) { - List values = this.targetMap.get(key); - return (values != null ? values.get(0) : null); - } - @Override public void set(K key, V value) { List values = new LinkedList<>(); diff --git a/spring-core/src/main/java/org/springframework/util/MultiValueMap.java b/spring-core/src/main/java/org/springframework/util/MultiValueMap.java index 011f06628d..be105d6123 100644 --- a/spring-core/src/main/java/org/springframework/util/MultiValueMap.java +++ b/spring-core/src/main/java/org/springframework/util/MultiValueMap.java @@ -32,7 +32,7 @@ public interface MultiValueMap extends Map> { /** * Return the first value for the given key. * @param key the key - * @return the first value for the specified key, or {@code null} + * @return the first value for the specified key, or {@code null} if none */ @Nullable V getFirst(K key); @@ -50,7 +50,7 @@ public interface MultiValueMap extends Map> { * @param values the values to be added * @since 5.0 */ - void addAll(K key, List values); + void addAll(K key, List values); /** * Set the given single value under the given key. diff --git a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java index b3856cb922..67eb7e0b95 100644 --- a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java @@ -119,7 +119,7 @@ public abstract class ReflectionUtils { * @param target the target object on which to set the field * @param value the value to set (may be {@code null}) */ - public static void setField(Field field, Object target, @Nullable Object value) { + public static void setField(Field field, @Nullable Object target, @Nullable Object value) { try { field.set(target, value); } diff --git a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java index d35343ecc5..0d447bd010 100644 --- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java +++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java @@ -56,6 +56,7 @@ import org.springframework.util.MultiValueMap; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import static org.mockito.BDDMockito.any; import static org.mockito.BDDMockito.*; /** @@ -86,7 +87,7 @@ public class ResolvableTypeTests { assertThat(none.getGenerics().length, equalTo(0)); assertThat(none.getInterfaces().length, equalTo(0)); assertThat(none.getSuperType(), equalTo(ResolvableType.NONE)); - assertThat(none.getType(), nullValue()); + assertThat(none.getType(), equalTo(ResolvableType.EmptyType.INSTANCE)); assertThat(none.hasGenerics(), equalTo(false)); assertThat(none.isArray(), equalTo(false)); assertThat(none.resolve(), nullValue()); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java index fc9564ced9..604296b97b 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java @@ -28,7 +28,6 @@ import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.handler.HandlerMethod; -import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -289,9 +288,7 @@ public class InvocableHandlerMethod extends HandlerMethod { @Override public Type getGenericParameterType() { - Type returnType = this.returnType.getType(); - Assert.state(returnType != null, "No return type"); - return returnType; + return this.returnType.getType(); } @Override diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java index 0bd025772c..499ace872f 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java @@ -417,7 +417,7 @@ public class StompHeaders implements MultiValueMap, Serializable } @Override - public void addAll(String headerName, List headerValues) { + public void addAll(String headerName, List headerValues) { List currentValues = headers.computeIfAbsent(headerName, k -> new LinkedList<>()); currentValues.addAll(headerValues); } diff --git a/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpResponse.java b/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpResponse.java index 5044215e1c..22eca1c38c 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpResponse.java +++ b/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,10 +72,7 @@ public class MockClientHttpResponse extends MockHttpInputMessage implements Clie @Override public void close() { try { - InputStream body = getBody(); - if (body != null) { - body.close(); - } + getBody().close(); } catch (IOException ex) { // ignore diff --git a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java index cceb4ae7e9..487088c028 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java @@ -72,7 +72,7 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest { super(uri, headers); this.httpMethod = httpMethod; - this.contextPath = (contextPath != null ? contextPath : ""); + this.contextPath = contextPath; this.cookies = cookies; this.remoteAddress = remoteAddress; this.body = Flux.from(body); diff --git a/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContext.java b/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContext.java index a4522c3a84..c7466d417f 100644 --- a/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContext.java +++ b/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ import javax.naming.OperationNotSupportedException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -80,7 +81,9 @@ public class SimpleNamingContext implements Context { * Create a new naming context with the given naming root, * the given name/object map, and the JNDI environment entries. */ - public SimpleNamingContext(String root, Hashtable boundObjects, Hashtable env) { + public SimpleNamingContext( + String root, Hashtable boundObjects, @Nullable Hashtable env) { + this.root = root; this.boundObjects = boundObjects; if (env != null) { diff --git a/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java b/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java index 58027c99e0..5668094d16 100644 --- a/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java +++ b/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.springframework.mock.jndi; import java.util.Hashtable; - import javax.naming.Context; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; @@ -195,7 +194,7 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder * @see SimpleNamingContext */ @Override - public InitialContextFactory createInitialContextFactory(Hashtable environment) { + public InitialContextFactory createInitialContextFactory(@Nullable Hashtable environment) { if (activated == null && environment != null) { Object icf = environment.get(Context.INITIAL_CONTEXT_FACTORY); if (icf != null) { diff --git a/spring-test/src/main/java/org/springframework/mock/web/HeaderValueHolder.java b/spring-test/src/main/java/org/springframework/mock/web/HeaderValueHolder.java index 8cbd8a3cc5..f8e8265011 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/HeaderValueHolder.java +++ b/spring-test/src/main/java/org/springframework/mock/web/HeaderValueHolder.java @@ -68,10 +68,12 @@ class HeaderValueHolder { return Collections.unmodifiableList(stringList); } + @Nullable public Object getValue() { return (!this.values.isEmpty() ? this.values.get(0) : null); } + @Nullable public String getStringValue() { return (!this.values.isEmpty() ? String.valueOf(this.values.get(0)) : null); } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockAsyncContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockAsyncContext.java index ba9511885e..a85dc2dd3c 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockAsyncContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockAsyncContext.java @@ -55,7 +55,7 @@ public class MockAsyncContext implements AsyncContext { private final List dispatchHandlers = new ArrayList<>(); - public MockAsyncContext(ServletRequest request, ServletResponse response) { + public MockAsyncContext(ServletRequest request, @Nullable ServletResponse response) { this.request = (HttpServletRequest) request; this.response = (HttpServletResponse) response; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java b/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java index 4b29bafd08..aaa5c69aec 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java @@ -24,6 +24,8 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyContent; +import org.springframework.lang.Nullable; + /** * Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class. * Only necessary for testing applications when testing custom JSP tags. @@ -60,12 +62,12 @@ public class MockBodyContent extends BodyContent { * @param response the servlet response to wrap * @param targetWriter the target Writer to wrap */ - public MockBodyContent(String content, HttpServletResponse response, Writer targetWriter) { + public MockBodyContent(String content, @Nullable HttpServletResponse response, @Nullable Writer targetWriter) { super(adaptJspWriter(targetWriter, response)); this.content = content; } - private static JspWriter adaptJspWriter(Writer targetWriter, HttpServletResponse response) { + private static JspWriter adaptJspWriter(@Nullable Writer targetWriter, @Nullable HttpServletResponse response) { if (targetWriter instanceof JspWriter) { return (JspWriter) targetWriter; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java b/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java index d9067f7d5c..0ff8c2f1bc 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java @@ -23,6 +23,7 @@ import java.util.Map; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -64,7 +65,7 @@ public class MockFilterConfig implements FilterConfig { * Create a new MockFilterConfig. * @param servletContext the ServletContext that the servlet runs in */ - public MockFilterConfig(ServletContext servletContext) { + public MockFilterConfig(@Nullable ServletContext servletContext) { this(servletContext, ""); } @@ -73,7 +74,7 @@ public class MockFilterConfig implements FilterConfig { * @param servletContext the ServletContext that the servlet runs in * @param filterName the name of the filter */ - public MockFilterConfig(ServletContext servletContext, String filterName) { + public MockFilterConfig(@Nullable ServletContext servletContext, String filterName) { this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); this.filterName = filterName; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java index d4f8342987..b6c2f7a842 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -41,7 +41,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; - import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; @@ -64,6 +63,7 @@ import org.springframework.util.Assert; import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.util.ObjectUtils; import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; @@ -370,6 +370,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getCharacterEncoding() { return this.characterEncoding; } @@ -449,7 +450,7 @@ public class MockHttpServletRequest implements HttpServletRequest { return getContentLength(); } - public void setContentType(String contentType) { + public void setContentType(@Nullable String contentType) { this.contentType = contentType; if (contentType != null) { try { @@ -470,6 +471,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getContentType() { return this.contentType; } @@ -530,7 +532,7 @@ public class MockHttpServletRequest implements HttpServletRequest { *

If there are already one or more values registered for the given * parameter name, the given value will be added to the end of the list. */ - public void addParameter(String name, String value) { + public void addParameter(String name, @Nullable String value) { addParameter(name, new String[] {value}); } @@ -591,8 +593,10 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getParameter(String name) { - String[] arr = (name != null ? this.parameters.get(name) : null); + Assert.notNull(name, "Parameter name must not be null"); + String[] arr = this.parameters.get(name); return (arr != null && arr.length > 0 ? arr[0] : null); } @@ -603,7 +607,8 @@ public class MockHttpServletRequest implements HttpServletRequest { @Override public String[] getParameterValues(String name) { - return (name != null ? this.parameters.get(name) : null); + Assert.notNull(name, "Parameter name must not be null"); + return this.parameters.get(name); } @Override @@ -709,7 +714,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override - public void setAttribute(String name, Object value) { + public void setAttribute(String name, @Nullable Object value) { checkActive(); Assert.notNull(name, "Attribute name must not be null"); if (value != null) { @@ -903,6 +908,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public AsyncContext getAsyncContext() { return this.asyncContext; } @@ -930,17 +936,18 @@ public class MockHttpServletRequest implements HttpServletRequest { return this.authType; } - public void setCookies(Cookie... cookies) { - this.cookies = cookies; + public void setCookies(@Nullable Cookie... cookies) { + this.cookies = (ObjectUtils.isEmpty(cookies) ? null : cookies); this.headers.remove(HttpHeaders.COOKIE); - if (cookies != null) { - Arrays.stream(cookies) + if (this.cookies != null) { + Arrays.stream(this.cookies) .map(c -> c.getName() + '=' + (c.getValue() == null ? "" : c.getValue())) .forEach(value -> doAddHeaderValue(HttpHeaders.COOKIE, value, false)); } } @Override + @Nullable public Cookie[] getCookies() { return this.cookies; } @@ -978,7 +985,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } } - private void doAddHeaderValue(String name, Object value, boolean replace) { + private void doAddHeaderValue(String name, @Nullable Object value, boolean replace) { HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); Assert.notNull(value, "Header value must not be null"); if (header == null || replace) { @@ -1045,6 +1052,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getHeader(String name) { HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); return (header != null ? header.getStringValue() : null); @@ -1098,6 +1106,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getPathTranslated() { return (this.pathInfo != null ? getRealPath(this.pathInfo) : null); } @@ -1111,7 +1120,7 @@ public class MockHttpServletRequest implements HttpServletRequest { return this.contextPath; } - public void setQueryString(String queryString) { + public void setQueryString(@Nullable String queryString) { this.queryString = queryString; } @@ -1120,7 +1129,7 @@ public class MockHttpServletRequest implements HttpServletRequest { return this.queryString; } - public void setRemoteUser(String remoteUser) { + public void setRemoteUser(@Nullable String remoteUser) { this.remoteUser = remoteUser; } @@ -1197,6 +1206,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public HttpSession getSession(boolean create) { checkActive(); // Reset session if invalidated. @@ -1211,6 +1221,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public HttpSession getSession() { return getSession(true); } @@ -1284,6 +1295,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public Part getPart(String name) throws IOException, IllegalStateException, ServletException { return this.parts.getFirst(name); } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java index 2a85175e59..4fcec47e8e 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java @@ -33,7 +33,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; - import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @@ -171,6 +170,7 @@ public class MockHttpServletResponse implements HttpServletResponse { } @Override + @Nullable public String getCharacterEncoding() { return this.characterEncoding; } @@ -224,7 +224,7 @@ public class MockHttpServletResponse implements HttpServletResponse { } @Override - public void setContentType(String contentType) { + public void setContentType(@Nullable String contentType) { this.contentType = contentType; if (contentType != null) { try { @@ -247,6 +247,7 @@ public class MockHttpServletResponse implements HttpServletResponse { } @Override + @Nullable public String getContentType() { return this.contentType; } @@ -302,7 +303,7 @@ public class MockHttpServletResponse implements HttpServletResponse { } @Override - public void setLocale(Locale locale) { + public void setLocale(@Nullable Locale locale) { this.locale = locale; if (locale != null) { doAddHeaderValue(HttpHeaders.ACCEPT_LANGUAGE, locale.toLanguageTag(), true); @@ -357,6 +358,7 @@ public class MockHttpServletResponse implements HttpServletResponse { return this.cookies.toArray(new Cookie[this.cookies.size()]); } + @Nullable public Cookie getCookie(String name) { Assert.notNull(name, "Cookie name must not be null"); for (Cookie cookie : this.cookies) { @@ -502,6 +504,7 @@ public class MockHttpServletResponse implements HttpServletResponse { setCommitted(true); } + @Nullable public String getRedirectedUrl() { return getHeader(HttpHeaders.LOCATION); } @@ -639,17 +642,19 @@ public class MockHttpServletResponse implements HttpServletResponse { this.forwardedUrl = forwardedUrl; } + @Nullable public String getForwardedUrl() { return this.forwardedUrl; } - public void setIncludedUrl(String includedUrl) { + public void setIncludedUrl(@Nullable String includedUrl) { this.includedUrls.clear(); if (includedUrl != null) { this.includedUrls.add(includedUrl); } } + @Nullable public String getIncludedUrl() { int count = this.includedUrls.size(); Assert.state(count <= 1, diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java index 81f43bb150..ddc43bcac2 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java @@ -29,6 +29,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -79,7 +80,7 @@ public class MockHttpSession implements HttpSession { * Create a new MockHttpSession. * @param servletContext the ServletContext that the session runs in */ - public MockHttpSession(ServletContext servletContext) { + public MockHttpSession(@Nullable ServletContext servletContext) { this(servletContext, null); } @@ -88,7 +89,7 @@ public class MockHttpSession implements HttpSession { * @param servletContext the ServletContext that the session runs in * @param id a unique identifier for this session */ - public MockHttpSession(ServletContext servletContext, String id) { + public MockHttpSession(@Nullable ServletContext servletContext, @Nullable String id) { this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); this.id = (id != null ? id : Integer.toString(nextId++)); } @@ -171,7 +172,7 @@ public class MockHttpSession implements HttpSession { } @Override - public void setAttribute(String name, Object value) { + public void setAttribute(String name, @Nullable Object value) { assertIsValid(); Assert.notNull(name, "Attribute name must not be null"); if (value != null) { diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java b/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java index 1245dbb5a8..6e5d47c2ae 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java @@ -22,6 +22,8 @@ import java.io.Writer; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspWriter; +import org.springframework.lang.Nullable; + /** * Mock implementation of the {@link javax.servlet.jsp.JspWriter} class. * Only necessary for testing applications when testing custom JSP tags. @@ -58,7 +60,7 @@ public class MockJspWriter extends JspWriter { * @param response the servlet response to wrap * @param targetWriter the target Writer to wrap */ - public MockJspWriter(HttpServletResponse response, Writer targetWriter) { + public MockJspWriter(@Nullable HttpServletResponse response, @Nullable Writer targetWriter) { super(DEFAULT_BUFFER, true); this.response = (response != null ? response : new MockHttpServletResponse()); if (targetWriter instanceof PrintWriter) { diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockMultipartFile.java b/spring-test/src/main/java/org/springframework/mock/web/MockMultipartFile.java index 91eb319f35..902940e581 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockMultipartFile.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockMultipartFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; @@ -53,7 +54,7 @@ public class MockMultipartFile implements MultipartFile { * @param name the name of the file * @param content the content of the file */ - public MockMultipartFile(String name, byte[] content) { + public MockMultipartFile(String name, @Nullable byte[] content) { this(name, "", null, content); } @@ -74,7 +75,9 @@ public class MockMultipartFile implements MultipartFile { * @param contentType the content type (if known) * @param content the content of the file */ - public MockMultipartFile(String name, String originalFilename, String contentType, byte[] content) { + public MockMultipartFile( + String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) { + Assert.hasLength(name, "Name must not be null"); this.name = name; this.originalFilename = (originalFilename != null ? originalFilename : ""); @@ -90,7 +93,8 @@ public class MockMultipartFile implements MultipartFile { * @param contentStream the content of the file as stream * @throws IOException if reading from the stream failed */ - public MockMultipartFile(String name, String originalFilename, String contentType, InputStream contentStream) + public MockMultipartFile( + String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream) throws IOException { this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream)); diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java index 7b31226583..37f4071030 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java @@ -36,6 +36,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -79,7 +80,7 @@ public class MockPageContext extends PageContext { * @param servletContext the ServletContext that the JSP page runs in * (only necessary when actually accessing the ServletContext) */ - public MockPageContext(ServletContext servletContext) { + public MockPageContext(@Nullable ServletContext servletContext) { this(servletContext, null, null, null); } @@ -90,7 +91,7 @@ public class MockPageContext extends PageContext { * @param request the current HttpServletRequest * (only necessary when actually accessing the request) */ - public MockPageContext(ServletContext servletContext, HttpServletRequest request) { + public MockPageContext(@Nullable ServletContext servletContext, @Nullable HttpServletRequest request) { this(servletContext, request, null, null); } @@ -101,7 +102,9 @@ public class MockPageContext extends PageContext { * @param response the current HttpServletResponse * (only necessary when actually writing to the response) */ - public MockPageContext(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response) { + public MockPageContext(@Nullable ServletContext servletContext, @Nullable HttpServletRequest request, + @Nullable HttpServletResponse response) { + this(servletContext, request, response, null); } @@ -112,8 +115,8 @@ public class MockPageContext extends PageContext { * @param response the current HttpServletResponse * @param servletConfig the ServletConfig (hardly ever accessed from within a tag) */ - public MockPageContext(ServletContext servletContext, HttpServletRequest request, - HttpServletResponse response, ServletConfig servletConfig) { + public MockPageContext(@Nullable ServletContext servletContext, @Nullable HttpServletRequest request, + @Nullable HttpServletResponse response, @Nullable ServletConfig servletConfig) { this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); this.request = (request != null ? request : new MockHttpServletRequest(servletContext)); @@ -135,7 +138,7 @@ public class MockPageContext extends PageContext { } @Override - public void setAttribute(String name, Object value) { + public void setAttribute(String name, @Nullable Object value) { Assert.notNull(name, "Attribute name must not be null"); if (value != null) { this.attributes.put(name, value); @@ -146,7 +149,7 @@ public class MockPageContext extends PageContext { } @Override - public void setAttribute(String name, Object value, int scope) { + public void setAttribute(String name, @Nullable Object value, int scope) { Assert.notNull(name, "Attribute name must not be null"); switch (scope) { case PAGE_SCOPE: @@ -167,12 +170,14 @@ public class MockPageContext extends PageContext { } @Override + @Nullable public Object getAttribute(String name) { Assert.notNull(name, "Attribute name must not be null"); return this.attributes.get(name); } @Override + @Nullable public Object getAttribute(String name, int scope) { Assert.notNull(name, "Attribute name must not be null"); switch (scope) { @@ -191,6 +196,7 @@ public class MockPageContext extends PageContext { } @Override + @Nullable public Object findAttribute(String name) { Object value = getAttribute(name); if (value == null) { @@ -267,7 +273,7 @@ public class MockPageContext extends PageContext { return this.request.getAttributeNames(); case SESSION_SCOPE: HttpSession session = this.request.getSession(false); - return (session != null ? session.getAttributeNames() : null); + return (session != null ? session.getAttributeNames() : Collections.emptyEnumeration()); case APPLICATION_SCOPE: return this.servletContext.getAttributeNames(); default: @@ -290,12 +296,14 @@ public class MockPageContext extends PageContext { } @Override + @Nullable public ELContext getELContext() { return null; } @Override @Deprecated + @Nullable public javax.servlet.jsp.el.VariableResolver getVariableResolver() { return null; } @@ -321,6 +329,7 @@ public class MockPageContext extends PageContext { } @Override + @Nullable public Exception getException() { return null; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockPart.java b/spring-test/src/main/java/org/springframework/mock/web/MockPart.java index cf7d898457..716cb99a7b 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockPart.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockPart.java @@ -20,14 +20,15 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collection; +import java.util.Collections; import javax.servlet.http.Part; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; - /** * Mock implementation of {@code javax.servlet.http.Part}. * @@ -55,7 +56,7 @@ public class MockPart implements Part { /** * Constructor for a part with a filename. */ - public MockPart(String name, String filename, InputStream content) throws IOException { + public MockPart(String name, @Nullable String filename, InputStream content) throws IOException { this(name, filename, FileCopyUtils.copyToByteArray(content)); } @@ -63,7 +64,7 @@ public class MockPart implements Part { * Constructor for a part with byte[] content only. * @see #getHeaders() */ - private MockPart(String name, String filename, byte[] content) { + private MockPart(String name, @Nullable String filename, @Nullable byte[] content) { Assert.hasLength(name, "Name must not be null"); this.name = name; this.filename = filename; @@ -83,6 +84,7 @@ public class MockPart implements Part { } @Override + @Nullable public String getContentType() { MediaType contentType = this.headers.getContentType(); return (contentType != null ? contentType.toString() : null); @@ -99,13 +101,15 @@ public class MockPart implements Part { } @Override + @Nullable public String getHeader(String name) { return this.headers.getFirst(name); } @Override public Collection getHeaders(String name) { - return this.headers.get(name); + Collection headerValues = this.headers.get(name); + return (headerValues != null ? headerValues : Collections.emptyList()); } @Override diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java b/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java index 805e7b4635..8391979ba8 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java @@ -23,6 +23,7 @@ import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -60,7 +61,7 @@ public class MockServletConfig implements ServletConfig { * Create a new MockServletConfig. * @param servletContext the ServletContext that the servlet runs in */ - public MockServletConfig(ServletContext servletContext) { + public MockServletConfig(@Nullable ServletContext servletContext) { this(servletContext, ""); } @@ -69,7 +70,7 @@ public class MockServletConfig implements ServletConfig { * @param servletContext the ServletContext that the servlet runs in * @param servletName the name of the servlet */ - public MockServletConfig(ServletContext servletContext, String servletName) { + public MockServletConfig(@Nullable ServletContext servletContext, String servletName) { this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); this.servletName = servletName; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java index 1857c5144a..3cf048f50a 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java @@ -182,7 +182,7 @@ public class MockServletContext implements ServletContext { */ public MockServletContext(String resourceBasePath, @Nullable ResourceLoader resourceLoader) { this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); - this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : ""); + this.resourceBasePath = resourceBasePath; // Use JVM temp dir as ServletContext temp dir. String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY); @@ -207,7 +207,7 @@ public class MockServletContext implements ServletContext { } public void setContextPath(String contextPath) { - this.contextPath = (contextPath != null ? contextPath : ""); + this.contextPath = contextPath; } @Override @@ -287,6 +287,7 @@ public class MockServletContext implements ServletContext { } @Override + @Nullable public Set getResourcePaths(String path) { String actualPath = (path.endsWith("/") ? path : path + "/"); Resource resource = this.resourceLoader.getResource(getResourceLocation(actualPath)); @@ -313,6 +314,7 @@ public class MockServletContext implements ServletContext { } @Override + @Nullable public URL getResource(String path) throws MalformedURLException { Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); if (!resource.exists()) { @@ -331,6 +333,7 @@ public class MockServletContext implements ServletContext { } @Override + @Nullable public InputStream getResourceAsStream(String path) { Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); if (!resource.exists()) { @@ -410,6 +413,7 @@ public class MockServletContext implements ServletContext { @Override @Deprecated + @Nullable public Servlet getServlet(String name) { return null; } @@ -443,6 +447,7 @@ public class MockServletContext implements ServletContext { } @Override + @Nullable public String getRealPath(String path) { Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); try { @@ -486,6 +491,7 @@ public class MockServletContext implements ServletContext { } @Override + @Nullable public Object getAttribute(String name) { Assert.notNull(name, "Attribute name must not be null"); return this.attributes.get(name); @@ -497,7 +503,7 @@ public class MockServletContext implements ServletContext { } @Override - public void setAttribute(String name, Object value) { + public void setAttribute(String name, @Nullable Object value) { Assert.notNull(name, "Attribute name must not be null"); if (value != null) { this.attributes.put(name, value); @@ -523,6 +529,7 @@ public class MockServletContext implements ServletContext { } @Override + @Nullable public ClassLoader getClassLoader() { return ClassUtils.getDefaultClassLoader(); } diff --git a/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java b/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java index 4cdaf53164..4a10360871 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java @@ -47,6 +47,7 @@ import org.springframework.web.server.WebSession; /** * Mock implementation of {@link ServerRequest}. + * * @author Arjen Poutsma * @since 5.0 */ @@ -70,9 +71,9 @@ public class MockServerRequest implements ServerRequest { private Principal principal; - private MockServerRequest(HttpMethod method, URI uri, - MockHeaders headers, @Nullable Object body, Map attributes, - MultiValueMap queryParams, + + private MockServerRequest(HttpMethod method, URI uri, MockHeaders headers, @Nullable Object body, + Map attributes, MultiValueMap queryParams, Map pathVariables, WebSession session, Principal principal) { this.method = method; @@ -104,25 +105,29 @@ public class MockServerRequest implements ServerRequest { @Override @SuppressWarnings("unchecked") - public S body(BodyExtractor extractor){ + public S body(BodyExtractor extractor) { + Assert.state(this.body != null, "No body"); return (S) this.body; } @Override @SuppressWarnings("unchecked") public S body(BodyExtractor extractor, Map hints) { + Assert.state(this.body != null, "No body"); return (S) this.body; } @Override @SuppressWarnings("unchecked") public Mono bodyToMono(Class elementClass) { + Assert.state(this.body != null, "No body"); return (Mono) this.body; } @Override @SuppressWarnings("unchecked") public Flux bodyToFlux(Class elementClass) { + Assert.state(this.body != null, "No body"); return (Flux) this.body; } diff --git a/spring-test/src/main/java/org/springframework/test/annotation/ProfileValueUtils.java b/spring-test/src/main/java/org/springframework/test/annotation/ProfileValueUtils.java index c7dd1a2c1e..669ccb610c 100644 --- a/spring-test/src/main/java/org/springframework/test/annotation/ProfileValueUtils.java +++ b/spring-test/src/main/java/org/springframework/test/annotation/ProfileValueUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,6 +77,7 @@ public abstract class ProfileValueUtils { } else { profileValueSourceType = (Class) AnnotationUtils.getDefaultValue(annotationType); + Assert.state(profileValueSourceType != null, "No default ProfileValueSource class"); } if (logger.isDebugEnabled()) { logger.debug("Retrieved ProfileValueSource type [" + profileValueSourceType + "] for class [" + diff --git a/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java index 669adbd65c..dff7db80f1 100644 --- a/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java +++ b/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -158,7 +158,7 @@ public @interface ContextConfiguration { * @see #inheritInitializers * @see #loader */ - Class>[] initializers() default {}; + Class>[] initializers() default {}; /** * Whether or not {@link #locations resource locations} or annotated diff --git a/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java b/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java index 58f0713e66..43410b239f 100644 --- a/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java +++ b/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,7 +58,7 @@ public class ContextConfigurationAttributes { private final boolean inheritLocations; - private final Class>[] initializers; + private final Class>[] initializers; private final boolean inheritInitializers; @@ -101,9 +101,10 @@ public class ContextConfigurationAttributes { */ @SuppressWarnings("unchecked") public ContextConfigurationAttributes(Class declaringClass, AnnotationAttributes annAttrs) { - this(declaringClass, annAttrs.getStringArray("locations"), annAttrs.getClassArray("classes"), annAttrs.getBoolean("inheritLocations"), - (Class>[]) annAttrs.getClassArray("initializers"), - annAttrs.getBoolean("inheritInitializers"), annAttrs.getString("name"), (Class) annAttrs.getClass("loader")); + this(declaringClass, annAttrs.getStringArray("locations"), annAttrs.getClassArray("classes"), + annAttrs.getBoolean("inheritLocations"), + (Class>[]) annAttrs.getClassArray("initializers"), + annAttrs.getBoolean("inheritInitializers"), annAttrs.getString("name"), annAttrs.getClass("loader")); } /** @@ -123,7 +124,7 @@ public class ContextConfigurationAttributes { */ public ContextConfigurationAttributes( Class declaringClass, String[] locations, Class[] classes, boolean inheritLocations, - Class>[] initializers, + Class>[] initializers, boolean inheritInitializers, Class contextLoaderClass) { this(declaringClass, locations, classes, inheritLocations, initializers, inheritInitializers, null, @@ -148,11 +149,11 @@ public class ContextConfigurationAttributes { */ public ContextConfigurationAttributes( Class declaringClass, String[] locations, Class[] classes, boolean inheritLocations, - Class>[] initializers, - boolean inheritInitializers, String name, Class contextLoaderClass) { + Class>[] initializers, + boolean inheritInitializers, @Nullable String name, Class contextLoaderClass) { - Assert.notNull(declaringClass, "declaringClass must not be null"); - Assert.notNull(contextLoaderClass, "contextLoaderClass must not be null"); + Assert.notNull(declaringClass, "'declaringClass' must not be null"); + Assert.notNull(contextLoaderClass, "'contextLoaderClass' must not be null"); if (!ObjectUtils.isEmpty(locations) && !ObjectUtils.isEmpty(classes) && logger.isDebugEnabled()) { logger.debug(String.format( @@ -199,13 +200,12 @@ public class ContextConfigurationAttributes { *

Note: this is a mutable property. The returned value may therefore * represent a processed value that does not match the original value * declared via {@link ContextConfiguration @ContextConfiguration}. - * @return the annotated classes; potentially {@code null} or empty + * @return the annotated classes (potentially {empty) * @see ContextConfiguration#classes * @see #setClasses(Class[]) */ - @Nullable public Class[] getClasses() { - return this.classes; + return (this.classes != null ? this.classes : new Class[0]); } /** @@ -234,14 +234,13 @@ public class ContextConfigurationAttributes { *

Note: this is a mutable property. The returned value may therefore * represent a processed value that does not match the original value * declared via {@link ContextConfiguration @ContextConfiguration}. - * @return the resource locations; potentially {@code null} or empty + * @return the resource locations (potentially empty) * @see ContextConfiguration#value * @see ContextConfiguration#locations - * @see #setLocations(String[]) + * @see #setLocations */ - @Nullable public String[] getLocations() { - return this.locations; + return (this.locations != null ? this.locations : new String[0]); } /** @@ -283,7 +282,7 @@ public class ContextConfigurationAttributes { * @return the {@code ApplicationContextInitializer} classes * @since 3.2 */ - public Class>[] getInitializers() { + public Class>[] getInitializers() { return this.initializers; } diff --git a/spring-test/src/main/java/org/springframework/test/context/ContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/ContextLoader.java index 49b97a94aa..2945aef3ee 100644 --- a/spring-test/src/main/java/org/springframework/test/context/ContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/ContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,7 +60,7 @@ public interface ContextLoader { * application context (can be {@code null} or empty) * @return an array of application context resource locations */ - String[] processLocations(Class clazz, @Nullable String... locations); + String[] processLocations(Class clazz, String... locations); /** * Loads a new {@link ApplicationContext context} based on the supplied diff --git a/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java index 22aabbcf90..23e4290e94 100644 --- a/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java +++ b/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ import java.util.Set; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.style.ToStringCreator; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -73,8 +72,8 @@ public class MergedContextConfiguration implements Serializable { private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - private static final Set>> EMPTY_INITIALIZER_CLASSES = - Collections.>> emptySet(); + private static final Set>> EMPTY_INITIALIZER_CLASSES = + Collections.>> emptySet(); private static final Set EMPTY_CONTEXT_CUSTOMIZERS = Collections. emptySet(); @@ -85,7 +84,7 @@ public class MergedContextConfiguration implements Serializable { private final Class[] classes; - private final Set>> contextInitializerClasses; + private final Set>> contextInitializerClasses; private final String[] activeProfiles; @@ -102,52 +101,9 @@ public class MergedContextConfiguration implements Serializable { private final MergedContextConfiguration parent; - private static String[] processStrings(String[] array) { - return (array != null ? array : EMPTY_STRING_ARRAY); - } - - private static Class[] processClasses(Class[] classes) { - return (classes != null ? classes : EMPTY_CLASS_ARRAY); - } - - private static Set>> processContextInitializerClasses( - Set>> contextInitializerClasses) { - - return (contextInitializerClasses != null ? - Collections.unmodifiableSet(contextInitializerClasses) : EMPTY_INITIALIZER_CLASSES); - } - - private static Set processContextCustomizers(Set contextCustomizers) { - return (contextCustomizers != null ? - Collections.unmodifiableSet(contextCustomizers) : EMPTY_CONTEXT_CUSTOMIZERS); - } - - private static String[] processActiveProfiles(String[] activeProfiles) { - if (activeProfiles == null) { - return EMPTY_STRING_ARRAY; - } - - // Active profiles must be unique - Set profilesSet = new LinkedHashSet<>(Arrays.asList(activeProfiles)); - return StringUtils.toStringArray(profilesSet); - } - - /** - * Generate a null-safe {@link String} representation of the supplied - * {@link ContextLoader} based solely on the fully qualified name of the - * loader or "null" if the supplied loader is {@code null}. - */ - @Nullable - protected static String nullSafeToString(@Nullable ContextLoader contextLoader) { - return (contextLoader != null ? contextLoader.getClass().getName() : "null"); - } - - /** * Create a new {@code MergedContextConfiguration} instance for the * supplied parameters. - *

Delegates to - * {@link #MergedContextConfiguration(Class, String[], Class[], Set, String[], String[], String[], ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration)}. * @param testClass the test class for which the configuration was merged * @param locations the merged context resource locations * @param classes the merged annotated classes @@ -163,18 +119,15 @@ public class MergedContextConfiguration implements Serializable { /** * Create a new {@code MergedContextConfiguration} instance for the * supplied parameters. - *

Delegates to - * {@link #MergedContextConfiguration(Class, String[], Class[], Set, String[], String[], String[], ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration)}. * @param testClass the test class for which the configuration was merged * @param locations the merged context resource locations * @param classes the merged annotated classes * @param contextInitializerClasses the merged context initializer classes * @param activeProfiles the merged active bean definition profiles * @param contextLoader the resolved {@code ContextLoader} - * @see #MergedContextConfiguration(Class, String[], Class[], Set, String[], ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration) */ public MergedContextConfiguration(Class testClass, String[] locations, Class[] classes, - Set>> contextInitializerClasses, + @Nullable Set>> contextInitializerClasses, String[] activeProfiles, ContextLoader contextLoader) { this(testClass, locations, classes, contextInitializerClasses, activeProfiles, contextLoader, null, null); @@ -183,8 +136,6 @@ public class MergedContextConfiguration implements Serializable { /** * Create a new {@code MergedContextConfiguration} instance for the * supplied parameters. - *

Delegates to - * {@link #MergedContextConfiguration(Class, String[], Class[], Set, String[], String[], String[], ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration)}. * @param testClass the test class for which the configuration was merged * @param locations the merged context resource locations * @param classes the merged annotated classes @@ -197,12 +148,13 @@ public class MergedContextConfiguration implements Serializable { * @since 3.2.2 */ public MergedContextConfiguration(Class testClass, String[] locations, Class[] classes, - Set>> contextInitializerClasses, + @Nullable Set>> contextInitializerClasses, String[] activeProfiles, ContextLoader contextLoader, - CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, @Nullable MergedContextConfiguration parent) { + @Nullable CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, + @Nullable MergedContextConfiguration parent) { - this(testClass, locations, classes, contextInitializerClasses, activeProfiles, null, null, contextLoader, - cacheAwareContextLoaderDelegate, parent); + this(testClass, locations, classes, contextInitializerClasses, activeProfiles, null, null, + contextLoader, cacheAwareContextLoaderDelegate, parent); } /** @@ -212,9 +164,9 @@ public class MergedContextConfiguration implements Serializable { */ public MergedContextConfiguration(MergedContextConfiguration mergedConfig) { this(mergedConfig.testClass, mergedConfig.locations, mergedConfig.classes, - mergedConfig.contextInitializerClasses, mergedConfig.activeProfiles, mergedConfig.propertySourceLocations, - mergedConfig.propertySourceProperties, mergedConfig.contextCustomizers, - mergedConfig.contextLoader, mergedConfig.cacheAwareContextLoaderDelegate, mergedConfig.parent); + mergedConfig.contextInitializerClasses, mergedConfig.activeProfiles, mergedConfig.propertySourceLocations, + mergedConfig.propertySourceProperties, mergedConfig.contextCustomizers, + mergedConfig.contextLoader, mergedConfig.cacheAwareContextLoaderDelegate, mergedConfig.parent); } /** @@ -241,10 +193,12 @@ public class MergedContextConfiguration implements Serializable { * @since 4.1 */ public MergedContextConfiguration(Class testClass, @Nullable String[] locations, @Nullable Class[] classes, - @Nullable Set>> contextInitializerClasses, - @Nullable String[] activeProfiles, @Nullable String[] propertySourceLocations, @Nullable String[] propertySourceProperties, - ContextLoader contextLoader, CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, + @Nullable Set>> contextInitializerClasses, + @Nullable String[] activeProfiles, @Nullable String[] propertySourceLocations, + @Nullable String[] propertySourceProperties, ContextLoader contextLoader, + @Nullable CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, @Nullable MergedContextConfiguration parent) { + this(testClass, locations, classes, contextInitializerClasses, activeProfiles, propertySourceLocations, propertySourceProperties, EMPTY_CONTEXT_CUSTOMIZERS, contextLoader, @@ -276,10 +230,11 @@ public class MergedContextConfiguration implements Serializable { * @since 4.3 */ public MergedContextConfiguration(Class testClass, @Nullable String[] locations, @Nullable Class[] classes, - @Nullable Set>> contextInitializerClasses, - @Nullable String[] activeProfiles, @Nullable String[] propertySourceLocations, @Nullable String[] propertySourceProperties, - @Nullable Set contextCustomizers, ContextLoader contextLoader, - CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, @Nullable MergedContextConfiguration parent) { + @Nullable Set>> contextInitializerClasses, + @Nullable String[] activeProfiles, @Nullable String[] propertySourceLocations, + @Nullable String[] propertySourceProperties, @Nullable Set contextCustomizers, + ContextLoader contextLoader, @Nullable CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, + @Nullable MergedContextConfiguration parent) { this.testClass = testClass; this.locations = processStrings(locations); @@ -361,7 +316,7 @@ public class MergedContextConfiguration implements Serializable { * Get the merged {@code ApplicationContextInitializer} classes for the * {@linkplain #getTestClass() test class}. */ - public Set>> getContextInitializerClasses() { + public Set>> getContextInitializerClasses() { return this.contextInitializerClasses; } @@ -455,7 +410,7 @@ public class MergedContextConfiguration implements Serializable { * {@link #getContextLoader() ContextLoaders}. */ @Override - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { if (this == other) { return true; } @@ -495,7 +450,7 @@ public class MergedContextConfiguration implements Serializable { return false; } - if (!nullSafeToString(this.contextLoader).equals(nullSafeToString(otherConfig.contextLoader))) { + if (!nullSafeClassName(this.contextLoader).equals(nullSafeClassName(otherConfig.contextLoader))) { return false; } @@ -517,7 +472,7 @@ public class MergedContextConfiguration implements Serializable { result = 31 * result + Arrays.hashCode(this.propertySourceProperties); result = 31 * result + this.contextCustomizers.hashCode(); result = 31 * result + (this.parent != null ? this.parent.hashCode() : 0); - result = 31 * result + nullSafeToString(this.contextLoader).hashCode(); + result = 31 * result + nullSafeClassName(this.contextLoader).hashCode(); return result; } @@ -543,9 +498,51 @@ public class MergedContextConfiguration implements Serializable { .append("propertySourceLocations", ObjectUtils.nullSafeToString(this.propertySourceLocations)) .append("propertySourceProperties", ObjectUtils.nullSafeToString(this.propertySourceProperties)) .append("contextCustomizers", this.contextCustomizers) - .append("contextLoader", nullSafeToString(this.contextLoader)) + .append("contextLoader", nullSafeClassName(this.contextLoader)) .append("parent", this.parent) .toString(); } + + private static String[] processStrings(@Nullable String[] array) { + return (array != null ? array : EMPTY_STRING_ARRAY); + } + + private static Class[] processClasses(@Nullable Class[] classes) { + return (classes != null ? classes : EMPTY_CLASS_ARRAY); + } + + private static Set>> processContextInitializerClasses( + @Nullable Set>> contextInitializerClasses) { + + return (contextInitializerClasses != null ? + Collections.unmodifiableSet(contextInitializerClasses) : EMPTY_INITIALIZER_CLASSES); + } + + private static Set processContextCustomizers( + @Nullable Set contextCustomizers) { + + return (contextCustomizers != null ? + Collections.unmodifiableSet(contextCustomizers) : EMPTY_CONTEXT_CUSTOMIZERS); + } + + private static String[] processActiveProfiles(@Nullable String[] activeProfiles) { + if (activeProfiles == null) { + return EMPTY_STRING_ARRAY; + } + + // Active profiles must be unique + Set profilesSet = new LinkedHashSet<>(Arrays.asList(activeProfiles)); + return StringUtils.toStringArray(profilesSet); + } + + /** + * Generate a null-safe {@link String} representation of the supplied + * {@link ContextLoader} based solely on the fully qualified name of the + * loader or "null" if the supplied loader is {@code null}. + */ + protected static String nullSafeClassName(@Nullable ContextLoader contextLoader) { + return (contextLoader != null ? contextLoader.getClass().getName() : "null"); + } + } diff --git a/spring-test/src/main/java/org/springframework/test/context/TestContext.java b/spring-test/src/main/java/org/springframework/test/context/TestContext.java index fa4ae78413..52634cd890 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestContext.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,24 +65,21 @@ public interface TestContext extends AttributeAccessor, Serializable { * @return the current test instance (may be {@code null}) * @see #updateState(Object, Method, Throwable) */ - @Nullable Object getTestInstance(); /** * Get the current {@linkplain Method test method} for this test context. *

Note: this is a mutable property. - * @return the current test method (may be {@code null}) + * @return the current test method * @see #updateState(Object, Method, Throwable) */ - @Nullable Method getTestMethod(); /** * Get the {@linkplain Throwable exception} that was thrown during execution * of the {@linkplain #getTestMethod() test method}. *

Note: this is a mutable property. - * @return the exception that was thrown, or {@code null} if no - * exception was thrown + * @return the exception that was thrown, or {@code null} if no exception was thrown * @see #updateState(Object, Method, Throwable) */ @Nullable @@ -101,14 +98,13 @@ public interface TestContext extends AttributeAccessor, Serializable { void markApplicationContextDirty(@Nullable HierarchyMode hierarchyMode); /** - * Update this test context to reflect the state of the currently executing - * test. + * Update this test context to reflect the state of the currently executing test. *

Caution: concurrent invocations of this method might not be thread-safe, * depending on the underlying implementation. * @param testInstance the current test instance (may be {@code null}) * @param testMethod the current test method (may be {@code null}) - * @param testException the exception that was thrown in the test method, or - * {@code null} if no exception was thrown + * @param testException the exception that was thrown in the test method, + * or {@code null} if no exception was thrown */ void updateState(@Nullable Object testInstance, @Nullable Method testMethod, @Nullable Throwable testException); diff --git a/spring-test/src/main/java/org/springframework/test/context/TestContextManager.java b/spring-test/src/main/java/org/springframework/test/context/TestContextManager.java index aa73e664dd..f50c0ebbca 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestContextManager.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestContextManager.java @@ -233,7 +233,6 @@ public class TestContextManager { * @see #getTestExecutionListeners() */ public void prepareTestInstance(Object testInstance) throws Exception { - Assert.notNull(testInstance, "Test instance must not be null"); if (logger.isTraceEnabled()) { logger.trace("prepareTestInstance(): instance [" + testInstance + "]"); } @@ -501,7 +500,6 @@ public class TestContextManager { } private void prepareForBeforeCallback(String callbackName, Object testInstance, Method testMethod) { - Assert.notNull(testInstance, "Test instance must not be null"); if (logger.isTraceEnabled()) { logger.trace(String.format("%s(): instance [%s], method [%s]", callbackName, testInstance, testMethod)); } @@ -509,8 +507,8 @@ public class TestContextManager { } private void prepareForAfterCallback(String callbackName, Object testInstance, Method testMethod, - Throwable exception) { - Assert.notNull(testInstance, "Test instance must not be null"); + @Nullable Throwable exception) { + if (logger.isTraceEnabled()) { logger.trace(String.format("%s(): instance [%s], method [%s], exception [%s]", callbackName, testInstance, testMethod, exception)); diff --git a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultContextCache.java b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultContextCache.java index 051acbbb50..a9afcedb81 100644 --- a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultContextCache.java +++ b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultContextCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -160,12 +160,14 @@ public class DefaultContextCache implements ContextCache { public void remove(MergedContextConfiguration key, @Nullable HierarchyMode hierarchyMode) { Assert.notNull(key, "Key must not be null"); - // startKey is the level at which to begin clearing the cache, depending - // on the configured hierarchy mode. + // startKey is the level at which to begin clearing the cache, + // depending on the configured hierarchy mode.s MergedContextConfiguration startKey = key; if (hierarchyMode == HierarchyMode.EXHAUSTIVE) { - while (startKey.getParent() != null) { - startKey = startKey.getParent(); + MergedContextConfiguration parent = startKey.getParent(); + while (parent != null) { + startKey = parent; + parent = startKey.getParent(); } } diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/AbstractExpressionEvaluatingCondition.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/AbstractExpressionEvaluatingCondition.java index 1111e7ec08..d24caccb0a 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/AbstractExpressionEvaluatingCondition.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/AbstractExpressionEvaluatingCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ContainerExecutionCondition; import org.junit.jupiter.api.extension.ExtensionContext; @@ -142,7 +141,8 @@ abstract class AbstractExpressionEvaluatingCondition implements ContainerExecuti if (loadContext) { applicationContext = SpringExtension.getApplicationContext(extensionContext); - } else { + } + else { gac = new GenericApplicationContext(); gac.refresh(); applicationContext = gac; @@ -150,7 +150,7 @@ abstract class AbstractExpressionEvaluatingCondition implements ContainerExecuti if (!(applicationContext instanceof ConfigurableApplicationContext)) { if (logger.isWarnEnabled()) { - String contextType = (applicationContext != null ? applicationContext.getClass().getName() : "null"); + String contextType = applicationContext.getClass().getName(); logger.warn(String.format("@%s(\"%s\") could not be evaluated on [%s] since the test " + "ApplicationContext [%s] is not a ConfigurableApplicationContext", annotationType.getSimpleName(), expression, element, contextType)); @@ -160,17 +160,18 @@ abstract class AbstractExpressionEvaluatingCondition implements ContainerExecuti ConfigurableBeanFactory configurableBeanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory(); BeanExpressionResolver expressionResolver = configurableBeanFactory.getBeanExpressionResolver(); + Assert.state(expressionResolver != null, "No BeanExpressionResolver"); BeanExpressionContext beanExpressionContext = new BeanExpressionContext(configurableBeanFactory, null); - Object result = expressionResolver.evaluate(configurableBeanFactory.resolveEmbeddedValue(expression), - beanExpressionContext); + Object result = expressionResolver.evaluate( + configurableBeanFactory.resolveEmbeddedValue(expression), beanExpressionContext); if (gac != null) { gac.close(); } if (result instanceof Boolean) { - return ((Boolean) result).booleanValue(); + return (Boolean) result; } else if (result instanceof String) { String str = ((String) result).trim().toLowerCase(); diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java index 79730cfcdc..3f4dd77dfa 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java @@ -39,6 +39,7 @@ import org.junit.jupiter.api.extension.TestInstancePostProcessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.lang.Nullable; import org.springframework.test.context.TestContextManager; import org.springframework.util.Assert; @@ -168,6 +169,7 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes * @see ParameterAutowireUtils#resolveDependency */ @Override + @Nullable public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext) { Parameter parameter = parameterContext.getParameter(); Class testClass = extensionContext.getTestClass().get(); diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.java index 74a0ee98b7..23760afc61 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.java @@ -73,7 +73,7 @@ public @interface SpringJUnitConfig { * Alias for {@link ContextConfiguration#initializers}. */ @AliasFor(annotation = ContextConfiguration.class) - Class>[] initializers() default {}; + Class>[] initializers() default {}; /** * Alias for {@link ContextConfiguration#inheritLocations}. diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.java index 29b78d59ef..19f0b92033 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/web/SpringJUnitWebConfig.java @@ -78,7 +78,7 @@ public @interface SpringJUnitWebConfig { * Alias for {@link ContextConfiguration#initializers}. */ @AliasFor(annotation = ContextConfiguration.class) - Class>[] initializers() default {}; + Class>[] initializers() default {}; /** * Alias for {@link ContextConfiguration#inheritLocations}. diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java b/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java index b6c533de52..2d9fd723b2 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi import org.springframework.test.jdbc.JdbcTestUtils; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; /** * Abstract {@linkplain Transactional transactional} extension of @@ -201,8 +202,10 @@ public abstract class AbstractTransactionalJUnit4SpringContextTests extends Abst * @see #setSqlScriptEncoding */ protected void executeSqlScript(String sqlResourcePath, boolean continueOnError) throws DataAccessException { + DataSource ds = this.jdbcTemplate.getDataSource(); + Assert.state(ds != null, "No DataSource set"); Resource resource = this.applicationContext.getResource(sqlResourcePath); - new ResourceDatabasePopulator(continueOnError, false, this.sqlScriptEncoding, resource).execute(jdbcTemplate.getDataSource()); + new ResourceDatabasePopulator(continueOnError, false, this.sqlScriptEncoding, resource).execute(ds); } } diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java b/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java index 6fbb224909..30749f1a6d 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,6 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.junit.Ignore; import org.junit.Test; import org.junit.internal.runners.model.ReflectiveCallable; @@ -107,7 +106,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner { withRulesMethod = ReflectionUtils.findMethod(SpringJUnit4ClassRunner.class, "withRules", FrameworkMethod.class, Object.class, Statement.class); - Assert.state(withRulesMethod != null, "SpringJUnit4ClassRunner requires JUnit 4.12 or higher."); + Assert.state(withRulesMethod != null, "SpringJUnit4ClassRunner requires JUnit 4.12 or higher"); ReflectionUtils.makeAccessible(withRulesMethod); } @@ -310,7 +309,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner { * Invoke JUnit's private {@code withRules()} method using reflection. */ private Statement withRulesReflectively(FrameworkMethod frameworkMethod, Object testInstance, Statement statement) { - return (Statement) ReflectionUtils.invokeMethod(withRulesMethod, this, frameworkMethod, testInstance, statement); + Object result = ReflectionUtils.invokeMethod(withRulesMethod, this, frameworkMethod, testInstance, statement); + Assert.state(result instanceof Statement, "withRules mismatch"); + return (Statement) result; } /** diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringMethodRule.java b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringMethodRule.java index c2dbe6e2bb..b22a03c62c 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringMethodRule.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringMethodRule.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import java.util.Optional; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.junit.ClassRule; import org.junit.rules.MethodRule; import org.junit.runners.model.FrameworkMethod; @@ -233,7 +232,9 @@ public class SpringMethodRule implements MethodRule { "SpringClassRule field [%s] must be annotated with JUnit's @ClassRule annotation. " + "Consult the javadoc for SpringClassRule for details.", ruleField)); - return (SpringClassRule) ReflectionUtils.getField(ruleField, null); + Object result = ReflectionUtils.getField(ruleField, null); + Assert.state(result instanceof SpringClassRule, "SpringClassRule field mismatch"); + return (SpringClassRule) result; } private static Optional findSpringClassRuleField(Class testClass) { diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java index 654217ac94..a9a37da57b 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java @@ -91,7 +91,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader { * @see #processLocations(Class, String...) */ @Override - public void processContextConfiguration(@Nullable ContextConfigurationAttributes configAttributes) { + public void processContextConfiguration(ContextConfigurationAttributes configAttributes) { String[] processedLocations = processLocations(configAttributes.getDeclaringClass(), configAttributes.getLocations()); configAttributes.setLocations(processedLocations); @@ -143,7 +143,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader { private void invokeApplicationContextInitializers(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { - Set>> initializerClasses = + Set>> initializerClasses = mergedConfig.getContextInitializerClasses(); if (initializerClasses.isEmpty()) { // no ApplicationContextInitializers have been declared -> nothing to do @@ -153,7 +153,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader { List> initializerInstances = new ArrayList<>(); Class contextClass = context.getClass(); - for (Class> initializerClass : initializerClasses) { + for (Class> initializerClass : initializerClasses) { Class initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class); if (initializerContextClass != null && !initializerContextClass.isInstance(context)) { @@ -213,7 +213,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader { * @see #processContextConfiguration(ContextConfigurationAttributes) */ @Override - public final String[] processLocations(Class clazz, @Nullable String... locations) { + public final String[] processLocations(Class clazz, String... locations) { return (ObjectUtils.isEmpty(locations) && isGenerateDefaultLocations()) ? generateDefaultLocations(clazz) : modifyLocations(clazz, locations); } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java index 43c62fe490..7291d1c6f7 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -300,6 +300,7 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot } // Return the last level in the context hierarchy + Assert.state(mergedConfig != null, "No merged context configuration"); return mergedConfig; } else { @@ -462,7 +463,6 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot Class contextLoaderClass = resolveExplicitContextLoaderClass(configAttributesList); if (contextLoaderClass == null) { contextLoaderClass = getDefaultContextLoaderClass(testClass); - Assert.state(contextLoaderClass != null, "getDefaultContextLoaderClass() must not return null"); } if (logger.isTraceEnabled()) { logger.trace(String.format("Using ContextLoader class [%s] for test class [%s]", diff --git a/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java index 676199b2a9..3585c996d0 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/ActiveProfilesUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import org.springframework.test.context.ActiveProfilesResolver; import org.springframework.test.util.MetaAnnotationUtils; import org.springframework.test.util.MetaAnnotationUtils.AnnotationDescriptor; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -107,16 +108,10 @@ abstract class ActiveProfilesUtils { } String[] profiles = resolver.resolve(rootDeclaringClass); - if (profiles == null) { - String msg = String.format( - "ActiveProfilesResolver [%s] returned a null array of bean definition profiles", - resolverClass.getName()); - logger.error(msg); - throw new IllegalStateException(msg); + if (!ObjectUtils.isEmpty(profiles)) { + profileArrays.add(profiles); } - profileArrays.add(profiles); - descriptor = (annotation.inheritProfiles() ? MetaAnnotationUtils.findAnnotationDescriptor( rootDeclaringClass.getSuperclass(), annotationType) : null); } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java index 073f8a25ac..e64d265822 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,6 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; import org.springframework.context.support.GenericApplicationContext; -import org.springframework.lang.Nullable; import org.springframework.test.context.ContextConfigurationAttributes; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.util.ObjectUtils; @@ -79,7 +78,7 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader * @see #detectDefaultConfigurationClasses(Class) */ @Override - public void processContextConfiguration(@Nullable ContextConfigurationAttributes configAttributes) { + public void processContextConfiguration(ContextConfigurationAttributes configAttributes) { if (!configAttributes.hasClasses() && isGenerateDefaultLocations()) { configAttributes.setClasses(detectDefaultConfigurationClasses(configAttributes.getDeclaringClass())); } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoaderUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoaderUtils.java index b5b0eb686b..0e5bde969b 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoaderUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoaderUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.lang.Nullable; import org.springframework.test.context.SmartContextLoader; import org.springframework.util.Assert; @@ -101,7 +102,7 @@ public abstract class AnnotationConfigContextLoaderUtils { * @param clazz the class to check * @return {@code true} if the supplied class meets the candidate criteria */ - private static boolean isDefaultConfigurationClassCandidate(Class clazz) { + private static boolean isDefaultConfigurationClassCandidate(@Nullable Class clazz) { return (clazz != null && isStaticNonPrivateAndNonFinal(clazz) && AnnotatedElementUtils.hasAnnotation(clazz, Configuration.class)); } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/ApplicationContextInitializerUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/ApplicationContextInitializerUtils.java index 013d3f7e6d..daecd4df4c 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/ApplicationContextInitializerUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/ApplicationContextInitializerUtils.java @@ -69,11 +69,11 @@ abstract class ApplicationContextInitializerUtils { * superclasses if appropriate (never {@code null}) * @since 3.2 */ - static Set>> resolveInitializerClasses( + static Set>> resolveInitializerClasses( List configAttributesList) { Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be empty"); - final Set>> initializerClasses = // + final Set>> initializerClasses = // new HashSet<>(); for (ContextConfigurationAttributes configAttributes : configAttributesList) { diff --git a/spring-test/src/main/java/org/springframework/test/context/support/ContextLoaderUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/ContextLoaderUtils.java index 6754a5bbe8..597643bc55 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/ContextLoaderUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/ContextLoaderUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,9 +130,11 @@ abstract class ContextLoaderUtils { } else if (contextHierarchyDeclaredLocally) { ContextHierarchy contextHierarchy = getAnnotation(declaringClass, contextHierarchyType); - for (ContextConfiguration contextConfiguration : contextHierarchy.value()) { - convertContextConfigToConfigAttributesAndAddToList( - contextConfiguration, rootDeclaringClass, configAttributesList); + if (contextHierarchy != null) { + for (ContextConfiguration contextConfiguration : contextHierarchy.value()) { + convertContextConfigToConfigAttributesAndAddToList( + contextConfiguration, rootDeclaringClass, configAttributesList); + } } } else { diff --git a/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java b/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java index 0f66bf0284..4aca49c0ce 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,15 +74,16 @@ public class DefaultTestContext implements TestContext { /** * Construct a new {@code DefaultTestContext} from the supplied arguments. - * @param testClass the test class for this test context; never {@code null} + * @param testClass the test class for this test context * @param mergedContextConfiguration the merged application context - * configuration for this test context; never {@code null} + * configuration for this test context * @param cacheAwareContextLoaderDelegate the delegate to use for loading - * and closing the application context for this test context; never {@code null} + * and closing the application context for this test context */ public DefaultTestContext(Class testClass, MergedContextConfiguration mergedContextConfiguration, CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) { - Assert.notNull(testClass, "testClass must not be null"); + + Assert.notNull(testClass, "Test Class must not be null"); Assert.notNull(mergedContextConfiguration, "MergedContextConfiguration must not be null"); Assert.notNull(cacheAwareContextLoaderDelegate, "CacheAwareContextLoaderDelegate must not be null"); this.testClass = testClass; @@ -132,10 +133,12 @@ public class DefaultTestContext implements TestContext { } public final Object getTestInstance() { + Assert.state(this.testInstance != null, "No test instance"); return this.testInstance; } public final Method getTestMethod() { + Assert.state(this.testMethod != null, "No test method"); return this.testMethod; } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/DependencyInjectionTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/support/DependencyInjectionTestExecutionListener.java index ba3bb7d25e..1c2eac6c83 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/DependencyInjectionTestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/DependencyInjectionTestExecutionListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java index aa18ccfaca..fab45d0fcd 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,12 +73,11 @@ class TestPropertySourceAttributes { private TestPropertySourceAttributes(Class declaringClass, String[] locations, boolean inheritLocations, String[] properties, boolean inheritProperties) { - Assert.notNull(declaringClass, "declaringClass must not be null"); + Assert.notNull(declaringClass, "declaringClass must not be null"); if (ObjectUtils.isEmpty(locations) && ObjectUtils.isEmpty(properties)) { locations = new String[] { detectDefaultPropertiesFile(declaringClass) }; } - this.declaringClass = declaringClass; this.locations = locations; this.inheritLocations = inheritLocations; @@ -86,44 +85,38 @@ class TestPropertySourceAttributes { this.inheritProperties = inheritProperties; } + /** * Get the {@linkplain Class class} that declared {@code @TestPropertySource}. - * * @return the declaring class; never {@code null} */ Class getDeclaringClass() { - return declaringClass; + return this.declaringClass; } /** * Get the resource locations that were declared via {@code @TestPropertySource}. - * *

Note: The returned value may represent a detected default * that does not match the original value declared via {@code @TestPropertySource}. - * - * @return the resource locations; potentially {@code null} or empty + * @return the resource locations; potentially empty * @see TestPropertySource#value * @see TestPropertySource#locations - * @see #setLocations(String[]) */ - @Nullable String[] getLocations() { - return locations; + return this.locations; } /** * Get the {@code inheritLocations} flag that was declared via {@code @TestPropertySource}. - * * @return the {@code inheritLocations} flag * @see TestPropertySource#inheritLocations */ boolean isInheritLocations() { - return inheritLocations; + return this.inheritLocations; } /** * Get the inlined properties that were declared via {@code @TestPropertySource}. - * * @return the inlined properties; potentially {@code null} or empty * @see TestPropertySource#properties */ @@ -134,7 +127,6 @@ class TestPropertySourceAttributes { /** * Get the {@code inheritProperties} flag that was declared via {@code @TestPropertySource}. - * * @return the {@code inheritProperties} flag * @see TestPropertySource#inheritProperties */ @@ -157,6 +149,7 @@ class TestPropertySourceAttributes { .toString(); } + /** * Detect a default properties file for the supplied class, as specified * in the class-level Javadoc for {@link TestPropertySource}. @@ -174,10 +167,10 @@ class TestPropertySourceAttributes { return prefixedResourcePath; } else { - String msg = String.format("Could not detect default properties file for test [%s]: " - + "%s does not exist. Either declare the 'locations' or 'properties' attributes " - + "of @TestPropertySource or make the default properties file available.", testClass.getName(), - classPathResource); + String msg = String.format("Could not detect default properties file for test [%s]: " + + "%s does not exist. Either declare the 'locations' or 'properties' attributes " + + "of @TestPropertySource or make the default properties file available.", testClass.getName(), + classPathResource); logger.error(msg); throw new IllegalStateException(msg); } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java index 0ac2553383..3c235cd53a 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -132,7 +132,10 @@ public abstract class TestPropertySourceUtils { if (logger.isTraceEnabled()) { logger.trace(String.format("Processing inlined properties for TestPropertySource attributes %s", attrs)); } - properties.addAll(0, Arrays.asList(attrs.getProperties())); + String[] attrProps = attrs.getProperties(); + if (attrProps != null) { + properties.addAll(0, Arrays.asList(attrProps)); + } if (!attrs.isInheritProperties()) { break; } diff --git a/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTransactionalTestNGSpringContextTests.java b/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTransactionalTestNGSpringContextTests.java index 0899e13bb5..ef1df23a1d 100644 --- a/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTransactionalTestNGSpringContextTests.java +++ b/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTransactionalTestNGSpringContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi import org.springframework.test.jdbc.JdbcTestUtils; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; /** * Abstract {@linkplain Transactional transactional} extension of @@ -185,8 +186,10 @@ public abstract class AbstractTransactionalTestNGSpringContextTests extends Abst * @see #setSqlScriptEncoding */ protected void executeSqlScript(String sqlResourcePath, boolean continueOnError) throws DataAccessException { + DataSource ds = this.jdbcTemplate.getDataSource(); + Assert.state(ds != null, "No DataSource set"); Resource resource = this.applicationContext.getResource(sqlResourcePath); - new ResourceDatabasePopulator(continueOnError, false, this.sqlScriptEncoding, resource).execute(jdbcTemplate.getDataSource()); + new ResourceDatabasePopulator(continueOnError, false, this.sqlScriptEncoding, resource).execute(ds); } } diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContext.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContext.java index 5f6cdbe40d..668ff8347f 100644 --- a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContext.java +++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.test.context.transaction; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.lang.Nullable; import org.springframework.test.context.TestContext; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; @@ -56,6 +57,7 @@ class TransactionContext { TransactionContext(TestContext testContext, PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition, boolean defaultRollback) { + this.testContext = testContext; this.transactionManager = transactionManager; this.transactionDefinition = transactionDefinition; @@ -63,6 +65,8 @@ class TransactionContext { this.flaggedForRollback = defaultRollback; } + + @Nullable TransactionStatus getTransactionStatus() { return this.transactionStatus; } @@ -83,7 +87,7 @@ class TransactionContext { } /** - * Start a new transaction for the configured {@linkplain #getTestContext test context}. + * Start a new transaction for the configured test context. *

Only call this method if {@link #endTransaction} has been called or if no * transaction has been previously started. * @throws TransactionException if starting the transaction fails @@ -102,9 +106,8 @@ class TransactionContext { } /** - * Immediately force a commit or rollback of the transaction - * for the configured {@linkplain #getTestContext test context}, according to - * the {@linkplain #isFlaggedForRollback rollback flag}. + * Immediately force a commit or rollback of the transaction for the + * configured test context, according to the {@linkplain #isFlaggedForRollback rollback flag}. */ void endTransaction() { if (logger.isTraceEnabled()) { @@ -133,4 +136,4 @@ class TransactionContext { } } -} \ No newline at end of file +} diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContextHolder.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContextHolder.java index 2cb89c6720..2932b50941 100644 --- a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContextHolder.java +++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionContextHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.test.context.transaction; import org.springframework.core.NamedInheritableThreadLocal; +import org.springframework.lang.Nullable; /** * {@link InheritableThreadLocal}-based holder for the current {@link TransactionContext}. @@ -26,18 +27,20 @@ import org.springframework.core.NamedInheritableThreadLocal; */ class TransactionContextHolder { - private static final ThreadLocal currentTransactionContext = new NamedInheritableThreadLocal<>( - "Test Transaction Context"); + private static final ThreadLocal currentTransactionContext = + new NamedInheritableThreadLocal<>("Test Transaction Context"); + static void setCurrentTransactionContext(@Nullable TransactionContext transactionContext) { + currentTransactionContext.set(transactionContext); + } + + @Nullable static TransactionContext getCurrentTransactionContext() { return currentTransactionContext.get(); } - static void setCurrentTransactionContext(TransactionContext transactionContext) { - currentTransactionContext.set(transactionContext); - } - + @Nullable static TransactionContext removeCurrentTransactionContext() { synchronized (currentTransactionContext) { TransactionContext transactionContext = currentTransactionContext.get(); diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java index ab07495021..ad7b10dfa6 100644 --- a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java @@ -31,6 +31,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils; import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.lang.Nullable; import org.springframework.test.annotation.Commit; import org.springframework.test.annotation.Rollback; import org.springframework.test.context.TestContext; @@ -156,8 +157,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis */ @Override public void beforeTestMethod(final TestContext testContext) throws Exception { - final Method testMethod = testContext.getTestMethod(); - final Class testClass = testContext.getTestClass(); + Method testMethod = testContext.getTestMethod(); + Class testClass = testContext.getTestClass(); Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null"); TransactionContext txContext = TransactionContextHolder.removeCurrentTransactionContext(); @@ -180,7 +181,6 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis } tm = getTransactionManager(testContext, transactionAttribute.getQualifier()); - Assert.state(tm != null, () -> String.format( "Failed to retrieve PlatformTransactionManager for @Transactional test for test context %s.", testContext)); @@ -212,7 +212,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis TransactionStatus transactionStatus = txContext.getTransactionStatus(); try { // If the transaction is still active... - if ((transactionStatus != null) && !transactionStatus.isCompleted()) { + if (transactionStatus != null && !transactionStatus.isCompleted()) { txContext.endTransaction(); } } @@ -306,6 +306,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis * @throws BeansException if an error occurs while retrieving the transaction manager * @see #getTransactionManager(TestContext) */ + @Nullable protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) { // Look up by type and qualifier from @Transactional if (StringUtils.hasText(qualifier)) { @@ -344,6 +345,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis * exists in the ApplicationContext * @see #getTransactionManager(TestContext, String) */ + @Nullable protected PlatformTransactionManager getTransactionManager(TestContext testContext) { return TestContextTransactionUtils.retrieveTransactionManager(testContext, null); } diff --git a/spring-test/src/main/java/org/springframework/test/context/util/TestContextResourceUtils.java b/spring-test/src/main/java/org/springframework/test/context/util/TestContextResourceUtils.java index eb1cba86a0..49d27fddde 100644 --- a/spring-test/src/main/java/org/springframework/test/context/util/TestContextResourceUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/util/TestContextResourceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,10 +47,6 @@ public abstract class TestContextResourceUtils { private static final String SLASH = "/"; - private TestContextResourceUtils() { - /* prevent instantiation */ - } - /** * Convert the supplied paths to classpath resource paths. * @@ -65,7 +61,6 @@ public abstract class TestContextResourceUtils { * {@link ResourceUtils#CLASSPATH_URL_PREFIX classpath:}, * {@link ResourceUtils#FILE_URL_PREFIX file:}, {@code http:}, etc.) will be * {@link StringUtils#cleanPath cleaned} but otherwise unmodified. - * * @param clazz the class with which the paths are associated * @param paths the paths to be converted * @return a new array of converted resource paths @@ -79,8 +74,8 @@ public abstract class TestContextResourceUtils { convertedPaths[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path; } else if (!ResourcePatternUtils.isUrl(path)) { - convertedPaths[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH - + StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path); + convertedPaths[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH + + StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path); } else { convertedPaths[i] = StringUtils.cleanPath(path); @@ -92,7 +87,6 @@ public abstract class TestContextResourceUtils { /** * Convert the supplied paths to an array of {@link Resource} handles using * the given {@link ResourceLoader}. - * * @param resourceLoader the {@code ResourceLoader} to use to convert the paths * @param paths the paths to be converted * @return a new array of resources @@ -106,7 +100,6 @@ public abstract class TestContextResourceUtils { /** * Convert the supplied paths to a list of {@link Resource} handles using * the given {@link ResourceLoader}. - * * @param resourceLoader the {@code ResourceLoader} to use to convert the paths * @param paths the paths to be converted * @return a new list of resources diff --git a/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java index 658112d636..659574aedd 100644 --- a/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; -import org.springframework.lang.Nullable; import org.springframework.test.context.ContextConfigurationAttributes; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.support.AnnotationConfigContextLoaderUtils; @@ -80,7 +79,7 @@ public class AnnotationConfigWebContextLoader extends AbstractGenericWebContextL * @see #detectDefaultConfigurationClasses(Class) */ @Override - public void processContextConfiguration(@Nullable ContextConfigurationAttributes configAttributes) { + public void processContextConfiguration(ContextConfigurationAttributes configAttributes) { if (!configAttributes.hasClasses() && isGenerateDefaultLocations()) { configAttributes.setClasses(detectDefaultConfigurationClasses(configAttributes.getDeclaringClass())); } diff --git a/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java index a91de16779..3e1999f6ce 100644 --- a/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java +++ b/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java @@ -99,7 +99,7 @@ public class WebMergedContextConfiguration extends MergedContextConfiguration { * @since 4.1 */ public WebMergedContextConfiguration(Class testClass, @Nullable String[] locations, @Nullable Class[] classes, - @Nullable Set>> contextInitializerClasses, + @Nullable Set>> contextInitializerClasses, @Nullable String[] activeProfiles, @Nullable String[] propertySourceLocations, @Nullable String[] propertySourceProperties, String resourceBasePath, ContextLoader contextLoader, CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, @Nullable MergedContextConfiguration parent) { @@ -135,7 +135,7 @@ public class WebMergedContextConfiguration extends MergedContextConfiguration { * @since 4.3 */ public WebMergedContextConfiguration(Class testClass, @Nullable String[] locations, @Nullable Class[] classes, - @Nullable Set>> contextInitializerClasses, + @Nullable Set>> contextInitializerClasses, @Nullable String[] activeProfiles, @Nullable String[] propertySourceLocations, @Nullable String[] propertySourceProperties, @Nullable Set contextCustomizers, String resourceBasePath, ContextLoader contextLoader, CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, @Nullable MergedContextConfiguration parent) { @@ -206,7 +206,7 @@ public class WebMergedContextConfiguration extends MergedContextConfiguration { .append("propertySourceProperties", ObjectUtils.nullSafeToString(getPropertySourceProperties())) .append("contextCustomizers", getContextCustomizers()) .append("resourceBasePath", getResourceBasePath()) - .append("contextLoader", nullSafeToString(getContextLoader())) + .append("contextLoader", nullSafeClassName(getContextLoader())) .append("parent", getParent()) .toString(); } diff --git a/spring-test/src/main/java/org/springframework/test/context/web/socket/MockServerContainerContextCustomizer.java b/spring-test/src/main/java/org/springframework/test/context/web/socket/MockServerContainerContextCustomizer.java index e68914eea5..a9b77a7480 100644 --- a/spring-test/src/main/java/org/springframework/test/context/web/socket/MockServerContainerContextCustomizer.java +++ b/spring-test/src/main/java/org/springframework/test/context/web/socket/MockServerContainerContextCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,10 @@ package org.springframework.test.context.web.socket; +import javax.servlet.ServletContext; + import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.lang.Nullable; import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.web.context.WebApplicationContext; @@ -35,12 +38,15 @@ class MockServerContainerContextCustomizer implements ContextCustomizer { public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { if (context instanceof WebApplicationContext) { WebApplicationContext wac = (WebApplicationContext) context; - wac.getServletContext().setAttribute("javax.websocket.server.ServerContainer", new MockServerContainer()); + ServletContext sc = wac.getServletContext(); + if (sc != null) { + sc.setAttribute("javax.websocket.server.ServerContainer", new MockServerContainer()); + } } } @Override - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { return (this == other || (other != null && getClass() == other.getClass())); } diff --git a/spring-test/src/main/java/org/springframework/test/jdbc/JdbcTestUtils.java b/spring-test/src/main/java/org/springframework/test/jdbc/JdbcTestUtils.java index be604dd7c6..4efd94f239 100644 --- a/spring-test/src/main/java/org/springframework/test/jdbc/JdbcTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/jdbc/JdbcTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,8 @@ public class JdbcTestUtils { * @return the number of rows in the table */ public static int countRowsInTable(JdbcTemplate jdbcTemplate, String tableName) { - return jdbcTemplate.queryForObject("SELECT COUNT(0) FROM " + tableName, Integer.class); + Integer result = jdbcTemplate.queryForObject("SELECT COUNT(0) FROM " + tableName, Integer.class); + return (result != null ? result : 0); } /** @@ -72,7 +73,8 @@ public class JdbcTestUtils { if (StringUtils.hasText(whereClause)) { sql += " WHERE " + whereClause; } - return jdbcTemplate.queryForObject(sql, Integer.class); + Integer result = jdbcTemplate.queryForObject(sql, Integer.class); + return (result != null ? result : 0); } /** @@ -112,14 +114,14 @@ public class JdbcTestUtils { * optionally the scale. * @return the number of rows deleted from the table */ - public static int deleteFromTableWhere(JdbcTemplate jdbcTemplate, String tableName, String whereClause, - Object... args) { + public static int deleteFromTableWhere( + JdbcTemplate jdbcTemplate, String tableName, String whereClause, Object... args) { String sql = "DELETE FROM " + tableName; if (StringUtils.hasText(whereClause)) { sql += " WHERE " + whereClause; } - int rowCount = (args != null && args.length > 0 ? jdbcTemplate.update(sql, args) : jdbcTemplate.update(sql)); + int rowCount = (args.length > 0 ? jdbcTemplate.update(sql, args) : jdbcTemplate.update(sql)); if (logger.isInfoEnabled()) { logger.info("Deleted " + rowCount + " rows from table " + tableName); } diff --git a/spring-test/src/main/java/org/springframework/test/util/AssertionErrors.java b/spring-test/src/main/java/org/springframework/test/util/AssertionErrors.java index 79649d7001..78f1f879d6 100644 --- a/spring-test/src/main/java/org/springframework/test/util/AssertionErrors.java +++ b/spring-test/src/main/java/org/springframework/test/util/AssertionErrors.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.test.util; +import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -50,7 +51,7 @@ public abstract class AssertionErrors { * @param expected expected value * @param actual actual value */ - public static void fail(String message, Object expected, Object actual) { + public static void fail(String message, @Nullable Object expected, @Nullable Object actual) { throw new AssertionError(message + " expected:<" + expected + "> but was:<" + actual + ">"); } @@ -76,7 +77,7 @@ public abstract class AssertionErrors { * @param expected the expected value * @param actual the actual value */ - public static void assertEquals(String message, Object expected, Object actual) { + public static void assertEquals(String message, @Nullable Object expected, @Nullable Object actual) { if (!ObjectUtils.nullSafeEquals(expected, actual)) { fail(message, ObjectUtils.nullSafeToString(expected), ObjectUtils.nullSafeToString(actual)); } @@ -92,7 +93,7 @@ public abstract class AssertionErrors { * @param expected the expected value * @param actual the actual value */ - public static void assertNotEquals(String message, Object expected, Object actual) { + public static void assertNotEquals(String message, @Nullable Object expected, @Nullable Object actual) { if (ObjectUtils.nullSafeEquals(expected, actual)) { throw new AssertionError(message + " was not expected to be:" + "<" + ObjectUtils.nullSafeToString(actual) + ">"); diff --git a/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java b/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java index 3fe7cb3f68..b5f76a0fce 100644 --- a/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java +++ b/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,6 @@ public class JsonExpectationsHelper { * are "similar" - i.e. they contain the same attribute-value pairs * regardless of formatting with a lenient checking (extensible, and non-strict * array ordering). - * * @param expected the expected JSON content * @param actual the actual JSON content * @since 4.1 @@ -48,13 +47,11 @@ public class JsonExpectationsHelper { * Parse the expected and actual strings as JSON and assert the two * are "similar" - i.e. they contain the same attribute-value pairs * regardless of formatting. - * *

Can compare in two modes, depending on {@code strict} parameter value: *

- * * @param expected the expected JSON content * @param actual the actual JSON content * @param strict enables strict checking @@ -69,7 +66,6 @@ public class JsonExpectationsHelper { * are "not similar" - i.e. they contain different attribute-value pairs * regardless of formatting with a lenient checking (extensible, and non-strict * array ordering). - * * @param expected the expected JSON content * @param actual the actual JSON content * @since 4.1 @@ -83,13 +79,11 @@ public class JsonExpectationsHelper { * Parse the expected and actual strings as JSON and assert the two * are "not similar" - i.e. they contain different attribute-value pairs * regardless of formatting. - * *

Can compare in two modes, depending on {@code strict} parameter value: *

    - *
  • {@code true}: strict checking. Not extensible, and strict array ordering.
  • - *
  • {@code false}: lenient checking. Extensible, and non-strict array ordering.
  • + *
  • {@code true}: strict checking. Not extensible, and strict array ordering.
  • + *
  • {@code false}: lenient checking. Extensible, and non-strict array ordering.
  • *
- * * @param expected the expected JSON content * @param actual the actual JSON content * @param strict enables strict checking diff --git a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java index 3bb3e49c88..4286665a85 100644 --- a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java +++ b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.Map; import com.jayway.jsonpath.JsonPath; import org.hamcrest.Matcher; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -95,7 +96,7 @@ public class JsonPathExpectationsHelper { * @param content the JSON content * @param expectedValue the expected value */ - public void assertValue(String content, Object expectedValue) { + public void assertValue(String content, @Nullable Object expectedValue) { Object actualValue = evaluateJsonPath(content); if ((actualValue instanceof List) && !(expectedValue instanceof List)) { @SuppressWarnings("rawtypes") @@ -231,11 +232,12 @@ public class JsonPathExpectationsHelper { assertTrue(failureReason("a non-empty value", value), !ObjectUtils.isEmpty(value)); } - private String failureReason(String expectedDescription, Object value) { + private String failureReason(String expectedDescription, @Nullable Object value) { return String.format("Expected %s at JSON path \"%s\" but found: %s", expectedDescription, this.expression, ObjectUtils.nullSafeToString(StringUtils.quoteIfString(value))); } + @Nullable private Object evaluateJsonPath(String content) { String message = "No value at JSON path \"" + this.expression + "\""; try { @@ -256,6 +258,7 @@ public class JsonPathExpectationsHelper { } } + @Nullable private Object assertExistsAndReturn(String content) { Object value = evaluateJsonPath(content); String reason = "No value at JSON path \"" + this.expression + "\""; diff --git a/spring-test/src/main/java/org/springframework/test/util/MetaAnnotationUtils.java b/spring-test/src/main/java/org/springframework/test/util/MetaAnnotationUtils.java index b0f0f03368..a627cb5c34 100644 --- a/spring-test/src/main/java/org/springframework/test/util/MetaAnnotationUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/MetaAnnotationUtils.java @@ -100,7 +100,7 @@ public abstract class MetaAnnotationUtils { */ @Nullable private static AnnotationDescriptor findAnnotationDescriptor( - Class clazz, Set visited, Class annotationType) { + @Nullable Class clazz, Set visited, Class annotationType) { Assert.notNull(annotationType, "Annotation type must not be null"); if (clazz == null || Object.class == clazz) { @@ -187,7 +187,7 @@ public abstract class MetaAnnotationUtils { */ @SuppressWarnings("unchecked") @Nullable - private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Class clazz, + private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(@Nullable Class clazz, Set visited, Class... annotationTypes) { assertNonEmptyAnnotationTypeArray(annotationTypes, "The list of annotation types must not be empty"); @@ -298,7 +298,7 @@ public abstract class MetaAnnotationUtils { } public AnnotationDescriptor(Class rootDeclaringClass, Class declaringClass, - Annotation composedAnnotation, T annotation) { + @Nullable Annotation composedAnnotation, T annotation) { Assert.notNull(rootDeclaringClass, "'rootDeclaringClass' must not be null"); Assert.notNull(annotation, "Annotation must not be null"); @@ -349,6 +349,7 @@ public abstract class MetaAnnotationUtils { return this.composedAnnotation; } + @Nullable public Class getComposedAnnotationType() { return (this.composedAnnotation != null ? this.composedAnnotation.annotationType() : null); } @@ -380,7 +381,7 @@ public abstract class MetaAnnotationUtils { } public UntypedAnnotationDescriptor(Class rootDeclaringClass, Class declaringClass, - Annotation composedAnnotation, Annotation annotation) { + @Nullable Annotation composedAnnotation, Annotation annotation) { super(rootDeclaringClass, declaringClass, composedAnnotation, annotation); } diff --git a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java index 49864f8412..113fc4dc42 100644 --- a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,7 +81,7 @@ public class ReflectionTestUtils { * @param name the name of the field to set; never {@code null} * @param value the value to set */ - public static void setField(Object targetObject, String name, Object value) { + public static void setField(Object targetObject, String name, @Nullable Object value) { setField(targetObject, name, value, null); } @@ -97,7 +97,7 @@ public class ReflectionTestUtils { * @param type the type of the field to set; may be {@code null} if * {@code name} is specified */ - public static void setField(Object targetObject, @Nullable String name, Object value, Class type) { + public static void setField(Object targetObject, @Nullable String name, @Nullable Object value, @Nullable Class type) { setField(targetObject, null, name, value, type); } @@ -112,7 +112,7 @@ public class ReflectionTestUtils { * @param value the value to set * @since 4.2 */ - public static void setField(Class targetClass, String name, Object value) { + public static void setField(Class targetClass, String name, @Nullable Object value) { setField(null, targetClass, name, value, null); } @@ -131,7 +131,9 @@ public class ReflectionTestUtils { * {@code name} is specified * @since 4.2 */ - public static void setField(Class targetClass, @Nullable String name, Object value, @Nullable Class type) { + public static void setField( + Class targetClass, @Nullable String name, @Nullable Object value, @Nullable Class type) { + setField(null, targetClass, name, value, type); } @@ -161,9 +163,11 @@ public class ReflectionTestUtils { * @see ReflectionUtils#setField(Field, Object, Object) * @see AopTestUtils#getUltimateTargetObject(Object) */ - public static void setField(@Nullable Object targetObject, @Nullable Class targetClass, @Nullable String name, Object value, @Nullable Class type) { + public static void setField(@Nullable Object targetObject, @Nullable Class targetClass, + @Nullable String name, @Nullable Object value, @Nullable Class type) { + Assert.isTrue(targetObject != null || targetClass != null, - "Either targetObject or targetClass for the field must be specified"); + "Either targetObject or targetClass for the field must be specified"); Object ultimateTarget = (targetObject != null ? AopTestUtils.getUltimateTargetObject(targetObject) : null); @@ -198,6 +202,7 @@ public class ReflectionTestUtils { * @return the field's current value * @see #getField(Class, String) */ + @Nullable public static Object getField(Object targetObject, String name) { return getField(targetObject, null, name); } @@ -214,6 +219,7 @@ public class ReflectionTestUtils { * @since 4.2 * @see #getField(Object, String) */ + @Nullable public static Object getField(Class targetClass, String name) { return getField(null, targetClass, name); } @@ -242,6 +248,7 @@ public class ReflectionTestUtils { * @see ReflectionUtils#getField(Field, Object) * @see AopTestUtils#getUltimateTargetObject(Object) */ + @Nullable public static Object getField(@Nullable Object targetObject, @Nullable Class targetClass, String name) { Assert.isTrue(targetObject != null || targetClass != null, "Either targetObject or targetClass for the field must be specified"); @@ -311,7 +318,7 @@ public class ReflectionTestUtils { * @see ReflectionUtils#makeAccessible(Method) * @see ReflectionUtils#invokeMethod(Method, Object, Object[]) */ - public static void invokeSetterMethod(Object target, String name, Object value, Class type) { + public static void invokeSetterMethod(Object target, String name, @Nullable Object value, @Nullable Class type) { Assert.notNull(target, "Target object must not be null"); Assert.hasText(name, "Method name must not be empty"); Class[] paramTypes = (type != null ? new Class[] {type} : null); @@ -361,6 +368,7 @@ public class ReflectionTestUtils { * @see ReflectionUtils#makeAccessible(Method) * @see ReflectionUtils#invokeMethod(Method, Object, Object[]) */ + @Nullable public static Object invokeGetterMethod(Object target, String name) { Assert.notNull(target, "Target object must not be null"); Assert.hasText(name, "Method name must not be empty"); @@ -404,7 +412,7 @@ public class ReflectionTestUtils { */ @SuppressWarnings("unchecked") @Nullable - public static T invokeMethod(Object target, String name, @Nullable Object... args) { + public static T invokeMethod(Object target, String name, Object... args) { Assert.notNull(target, "Target object must not be null"); Assert.hasText(name, "Method name must not be empty"); @@ -428,13 +436,13 @@ public class ReflectionTestUtils { } } - private static String safeToString(Object target) { + private static String safeToString(@Nullable Object target) { try { return String.format("target object [%s]", target); } catch (Exception ex) { return String.format("target of type [%s] whose toString() method threw [%s]", - (target != null ? target.getClass().getName() : "unknown"), ex); + (target != null ? target.getClass().getName() : "unknown"), ex); } } diff --git a/spring-test/src/main/java/org/springframework/test/util/XpathExpectationsHelper.java b/spring-test/src/main/java/org/springframework/test/util/XpathExpectationsHelper.java index 89f6c2bf3e..3b7ae51037 100644 --- a/spring-test/src/main/java/org/springframework/test/util/XpathExpectationsHelper.java +++ b/spring-test/src/main/java/org/springframework/test/util/XpathExpectationsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ package org.springframework.test.util; import java.io.ByteArrayInputStream; import java.util.Collections; import java.util.Map; - import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -75,7 +74,7 @@ public class XpathExpectationsHelper { } - private XPathExpression compileXpathExpression(String expression, Map namespaces) + private XPathExpression compileXpathExpression(String expression, @Nullable Map namespaces) throws XPathExpressionException { SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext(); @@ -96,7 +95,9 @@ public class XpathExpectationsHelper { * Parse the content, evaluate the XPath expression as a {@link Node}, * and assert it with the given {@code Matcher}. */ - public void assertNode(byte[] content, String encoding, final Matcher matcher) throws Exception { + public void assertNode(byte[] content, @Nullable String encoding, final Matcher matcher) + throws Exception { + Document document = parseXmlByteArray(content, encoding); Node node = evaluateXpath(document, XPathConstants.NODE, Node.class); assertThat("XPath " + this.expression, node, matcher); @@ -108,7 +109,7 @@ public class XpathExpectationsHelper { * @param encoding optional content encoding, if provided as metadata (e.g. in HTTP headers) * @return the parsed document */ - protected Document parseXmlByteArray(byte[] xml, String encoding) throws Exception { + protected Document parseXmlByteArray(byte[] xml, @Nullable String encoding) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(this.hasNamespaces); DocumentBuilder documentBuilder = factory.newDocumentBuilder(); @@ -124,6 +125,7 @@ public class XpathExpectationsHelper { * @throws XPathExpressionException */ @SuppressWarnings("unchecked") + @Nullable protected T evaluateXpath(Document document, QName evaluationType, Class expectedClass) throws XPathExpressionException { @@ -134,7 +136,7 @@ public class XpathExpectationsHelper { * Apply the XPath expression and assert the resulting content exists. * @throws Exception if content parsing or expression evaluation fails */ - public void exists(byte[] content, String encoding) throws Exception { + public void exists(byte[] content, @Nullable String encoding) throws Exception { Document document = parseXmlByteArray(content, encoding); Node node = evaluateXpath(document, XPathConstants.NODE, Node.class); assertTrue("XPath " + this.expression + " does not exist", node != null); @@ -144,7 +146,7 @@ public class XpathExpectationsHelper { * Apply the XPath expression and assert the resulting content does not exist. * @throws Exception if content parsing or expression evaluation fails */ - public void doesNotExist(byte[] content, String encoding) throws Exception { + public void doesNotExist(byte[] content, @Nullable String encoding) throws Exception { Document document = parseXmlByteArray(content, encoding); Node node = evaluateXpath(document, XPathConstants.NODE, Node.class); assertTrue("XPath " + this.expression + " exists", node == null); @@ -155,20 +157,22 @@ public class XpathExpectationsHelper { * given Hamcrest matcher. * @throws Exception if content parsing or expression evaluation fails */ - public void assertNodeCount(byte[] content, String encoding, Matcher matcher) throws Exception { + public void assertNodeCount(byte[] content, @Nullable String encoding, Matcher matcher) throws Exception { Document document = parseXmlByteArray(content, encoding); NodeList nodeList = evaluateXpath(document, XPathConstants.NODESET, NodeList.class); - assertThat("nodeCount for XPath " + this.expression, nodeList.getLength(), matcher); + assertThat("nodeCount for XPath " + this.expression, + (nodeList != null ? nodeList.getLength() : 0), matcher); } /** * Apply the XPath expression and assert the resulting content as an integer. * @throws Exception if content parsing or expression evaluation fails */ - public void assertNodeCount(byte[] content, String encoding, int expectedCount) throws Exception { + public void assertNodeCount(byte[] content, @Nullable String encoding, int expectedCount) throws Exception { Document document = parseXmlByteArray(content, encoding); NodeList nodeList = evaluateXpath(document, XPathConstants.NODESET, NodeList.class); - assertEquals("nodeCount for XPath " + this.expression, expectedCount, nodeList.getLength()); + assertEquals("nodeCount for XPath " + this.expression, expectedCount, + (nodeList != null ? nodeList.getLength() : 0)); } /** @@ -176,7 +180,7 @@ public class XpathExpectationsHelper { * given Hamcrest matcher. * @throws Exception if content parsing or expression evaluation fails */ - public void assertString(byte[] content, String encoding, Matcher matcher) throws Exception { + public void assertString(byte[] content, @Nullable String encoding, Matcher matcher) throws Exception { Document document = parseXmlByteArray(content, encoding); String result = evaluateXpath(document, XPathConstants.STRING, String.class); assertThat("XPath " + this.expression, result, matcher); @@ -186,7 +190,7 @@ public class XpathExpectationsHelper { * Apply the XPath expression and assert the resulting content as a String. * @throws Exception if content parsing or expression evaluation fails */ - public void assertString(byte[] content, String encoding, String expectedValue) throws Exception { + public void assertString(byte[] content, @Nullable String encoding, String expectedValue) throws Exception { Document document = parseXmlByteArray(content, encoding); String actual = evaluateXpath(document, XPathConstants.STRING, String.class); assertEquals("XPath " + this.expression, expectedValue, actual); @@ -197,7 +201,7 @@ public class XpathExpectationsHelper { * given Hamcrest matcher. * @throws Exception if content parsing or expression evaluation fails */ - public void assertNumber(byte[] content, String encoding, Matcher matcher) throws Exception { + public void assertNumber(byte[] content, @Nullable String encoding, Matcher matcher) throws Exception { Document document = parseXmlByteArray(content, encoding); Double result = evaluateXpath(document, XPathConstants.NUMBER, Double.class); assertThat("XPath " + this.expression, result, matcher); @@ -207,7 +211,7 @@ public class XpathExpectationsHelper { * Apply the XPath expression and assert the resulting content as a Double. * @throws Exception if content parsing or expression evaluation fails */ - public void assertNumber(byte[] content, String encoding, Double expectedValue) throws Exception { + public void assertNumber(byte[] content, @Nullable String encoding, Double expectedValue) throws Exception { Document document = parseXmlByteArray(content, encoding); Double actual = evaluateXpath(document, XPathConstants.NUMBER, Double.class); assertEquals("XPath " + this.expression, expectedValue, actual); @@ -217,7 +221,7 @@ public class XpathExpectationsHelper { * Apply the XPath expression and assert the resulting content as a Boolean. * @throws Exception if content parsing or expression evaluation fails */ - public void assertBoolean(byte[] content, String encoding, boolean expectedValue) throws Exception { + public void assertBoolean(byte[] content, @Nullable String encoding, boolean expectedValue) throws Exception { Document document = parseXmlByteArray(content, encoding); String actual = evaluateXpath(document, XPathConstants.STRING, String.class); assertEquals("XPath " + this.expression, expectedValue, Boolean.parseBoolean(actual)); diff --git a/spring-test/src/main/java/org/springframework/test/web/ModelAndViewAssert.java b/spring-test/src/main/java/org/springframework/test/web/ModelAndViewAssert.java index e8f7165fd1..3ca4ec5ee8 100644 --- a/spring-test/src/main/java/org/springframework/test/web/ModelAndViewAssert.java +++ b/spring-test/src/main/java/org/springframework/test/web/ModelAndViewAssert.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,30 +48,30 @@ public abstract class ModelAndViewAssert { * Checks whether the model value under the given {@code modelName} * exists and checks it type, based on the {@code expectedType}. If the * model entry exists and the type matches, the model value is returned. - * * @param mav ModelAndView to test against (never {@code null}) - * @param modelName name of the object to add to the model (never - * {@code null}) + * @param modelName name of the object to add to the model (never {@code null}) * @param expectedType expected type of the model value * @return the model value */ @SuppressWarnings("unchecked") public static T assertAndReturnModelAttributeOfType(ModelAndView mav, String modelName, Class expectedType) { - assertTrue("ModelAndView is null", mav != null); - assertTrue("Model is null", mav.getModel() != null); - Object obj = mav.getModel().get(modelName); - assertTrue("Model attribute with name '" + modelName + "' is null", obj != null); - assertTrue("Model attribute is not of expected type '" + expectedType.getName() + "' but rather of type '" - + obj.getClass().getName() + "'", expectedType.isAssignableFrom(obj.getClass())); + if (mav == null) { + fail("ModelAndView is null"); + } + Map model = mav.getModel(); + Object obj = model.get(modelName); + if (obj == null) { + fail("Model attribute with name '" + modelName + "' is null"); + } + assertTrue("Model attribute is not of expected type '" + expectedType.getName() + "' but rather of type '" + + obj.getClass().getName() + "'", expectedType.isAssignableFrom(obj.getClass())); return (T) obj; } /** * Compare each individual entry in a list, without first sorting the lists. - * * @param mav ModelAndView to test against (never {@code null}) - * @param modelName name of the object to add to the model (never - * {@code null}) + * @param modelName name of the object to add to the model (never {@code null}) * @param expectedList the expected list */ @SuppressWarnings("rawtypes") @@ -87,55 +87,53 @@ public abstract class ModelAndViewAssert { /** * Assert whether or not a model attribute is available. - * * @param mav ModelAndView to test against (never {@code null}) - * @param modelName name of the object to add to the model (never - * {@code null}) + * @param modelName name of the object to add to the model (never {@code null}) */ public static void assertModelAttributeAvailable(ModelAndView mav, String modelName) { - assertTrue("ModelAndView is null", mav != null); - assertTrue("Model is null", mav.getModel() != null); - assertTrue("Model attribute with name '" + modelName + "' is not available", - mav.getModel().containsKey(modelName)); + if (mav == null) { + fail("ModelAndView is null"); + } + Map model = mav.getModel(); + assertTrue("Model attribute with name '" + modelName + "' is not available", model.containsKey(modelName)); } /** * Compare a given {@code expectedValue} to the value from the model * bound under the given {@code modelName}. - * * @param mav ModelAndView to test against (never {@code null}) - * @param modelName name of the object to add to the model (never - * {@code null}) + * @param modelName name of the object to add to the model (never {@code null}) * @param expectedValue the model value */ public static void assertModelAttributeValue(ModelAndView mav, String modelName, Object expectedValue) { assertTrue("ModelAndView is null", mav != null); Object modelValue = assertAndReturnModelAttributeOfType(mav, modelName, Object.class); - assertTrue("Model value with name '" + modelName + "' is not the same as the expected value which was '" - + expectedValue + "'", modelValue.equals(expectedValue)); + assertTrue("Model value with name '" + modelName + "' is not the same as the expected value which was '" + + expectedValue + "'", modelValue.equals(expectedValue)); } /** * Inspect the {@code expectedModel} to see if all elements in the * model appear and are equal. - * * @param mav ModelAndView to test against (never {@code null}) * @param expectedModel the expected model */ public static void assertModelAttributeValues(ModelAndView mav, Map expectedModel) { - assertTrue("ModelAndView is null", mav != null); - assertTrue("Model is null", mav.getModel() != null); + if (mav == null) { + fail("ModelAndView is null"); + } + Map model = mav.getModel(); - if (!mav.getModel().keySet().equals(expectedModel.keySet())) { + if (!model.keySet().equals(expectedModel.keySet())) { StringBuilder sb = new StringBuilder("Keyset of expected model does not match.\n"); - appendNonMatchingSetsErrorMessage(expectedModel.keySet(), mav.getModel().keySet(), sb); + appendNonMatchingSetsErrorMessage(expectedModel.keySet(), model.keySet(), sb); fail(sb.toString()); } StringBuilder sb = new StringBuilder(); - for (String modelName : mav.getModel().keySet()) { + for (String modelName : model.keySet()) { Object assertionValue = expectedModel.get(modelName); - Object mavValue = mav.getModel().get(modelName); + Object mavValue = model.get(modelName); if (!assertionValue.equals(mavValue)) { sb.append("Value under name '").append(modelName).append("' differs, should have been '").append( assertionValue).append("' but was '").append(mavValue).append("'\n"); @@ -151,18 +149,15 @@ public abstract class ModelAndViewAssert { /** * Compare each individual entry in a list after having sorted both lists * (optionally using a comparator). - * * @param mav ModelAndView to test against (never {@code null}) - * @param modelName name of the object to add to the model (never - * {@code null}) + * @param modelName name of the object to add to the model (never {@code null}) * @param expectedList the expected list - * @param comparator the comparator to use (may be {@code null}). If - * not specifying the comparator, both lists will be sorted not using any - * comparator. + * @param comparator the comparator to use (may be {@code null}). If not + * specifying the comparator, both lists will be sorted not using any comparator. */ @SuppressWarnings({ "unchecked", "rawtypes" }) - public static void assertSortAndCompareListModelAttribute(ModelAndView mav, String modelName, List expectedList, - Comparator comparator) { + public static void assertSortAndCompareListModelAttribute( + ModelAndView mav, String modelName, List expectedList, Comparator comparator) { assertTrue("ModelAndView is null", mav != null); List modelList = assertAndReturnModelAttributeOfType(mav, modelName, List.class); @@ -187,18 +182,20 @@ public abstract class ModelAndViewAssert { /** * Check to see if the view name in the ModelAndView matches the given * {@code expectedName}. - * * @param mav ModelAndView to test against (never {@code null}) * @param expectedName the name of the model value */ public static void assertViewName(ModelAndView mav, String expectedName) { - assertTrue("ModelAndView is null", mav != null); + if (mav == null) { + fail("ModelAndView is null"); + } assertTrue("View name is not equal to '" + expectedName + "' but was '" + mav.getViewName() + "'", ObjectUtils.nullSafeEquals(expectedName, mav.getViewName())); } - private static void appendNonMatchingSetsErrorMessage(Set assertionSet, Set incorrectSet, - StringBuilder sb) { + + private static void appendNonMatchingSetsErrorMessage( + Set assertionSet, Set incorrectSet, StringBuilder sb) { Set tempSet = new HashSet<>(); tempSet.addAll(incorrectSet); diff --git a/spring-test/src/main/java/org/springframework/test/web/client/match/ContentRequestMatchers.java b/spring-test/src/main/java/org/springframework/test/web/client/match/ContentRequestMatchers.java index 7961c943e8..7bd05340c4 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/match/ContentRequestMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/match/ContentRequestMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -98,8 +98,10 @@ public class ContentRequestMatchers { public void match(ClientHttpRequest request) throws IOException, AssertionError { MediaType actualContentType = request.getHeaders().getContentType(); assertTrue("Content type not set", actualContentType != null); - assertTrue("Content type [" + actualContentType + "] is not compatible with [" + contentType + "]", - actualContentType.isCompatibleWith(contentType)); + if (actualContentType != null) { + assertTrue("Content type [" + actualContentType + "] is not compatible with [" + contentType + "]", + actualContentType.isCompatibleWith(contentType)); + } } }; } diff --git a/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java b/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java index 0b6b52e03a..a426c85e52 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java @@ -180,8 +180,10 @@ public abstract class MockRestRequestMatchers { @Override public void match(ClientHttpRequest request) { assertValueCount("header", name, request.getHeaders(), matchers.length); - for (int i = 0 ; i < matchers.length; i++) { - assertThat("Request header", request.getHeaders().get(name).get(i), matchers[i]); + List headerValues = request.getHeaders().get(name); + Assert.state(headerValues != null, "No header values"); + for (int i = 0; i < matchers.length; i++) { + assertThat("Request header [" + name + "]", headerValues.get(i), matchers[i]); } } }; @@ -195,9 +197,10 @@ public abstract class MockRestRequestMatchers { @Override public void match(ClientHttpRequest request) { assertValueCount("header", name, request.getHeaders(), expectedValues.length); + List headerValues = request.getHeaders().get(name); + Assert.state(headerValues != null, "No header values"); for (int i = 0 ; i < expectedValues.length; i++) { - assertEquals("Request header + [" + name + "]", - expectedValues[i], request.getHeaders().get(name).get(i)); + assertEquals("Request header [" + name + "]", expectedValues[i], headerValues.get(i)); } } }; diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultRouterFunctionSpec.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultRouterFunctionSpec.java index 2b42656877..85235bb1cb 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultRouterFunctionSpec.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultRouterFunctionSpec.java @@ -43,9 +43,7 @@ class DefaultRouterFunctionSpec extends AbstractMockServerSpec EntityExchangeResult decode(ResolvableType bodyType) { T body = (T) this.response.body(toMono(bodyType)).block(this.timeout); @@ -318,7 +311,6 @@ class DefaultWebTestClient implements WebTestClient { byte[] body = (resource != null ? resource.getByteArray() : null); return new EntityExchangeResult<>(this, body); } - } @@ -326,7 +318,6 @@ class DefaultWebTestClient implements WebTestClient { private final UndecodedExchangeResult result; - DefaultResponseSpec(ExchangeResult result, ClientResponse response, String uriTemplate, Duration timeout) { this.result = new UndecodedExchangeResult(result, response, uriTemplate, timeout); } @@ -342,13 +333,15 @@ class DefaultWebTestClient implements WebTestClient { } @Override + @SuppressWarnings("unchecked") public BodySpec expectBody(Class bodyType) { - return expectBody(ResolvableType.forClass(bodyType)); + return (BodySpec) expectBody(ResolvableType.forClass(bodyType)); } @Override + @SuppressWarnings({"rawtypes", "unchecked"}) public BodySpec expectBody(ResolvableType bodyType) { - return new DefaultBodySpec<>(this.result.decode(bodyType)); + return new DefaultBodySpec(this.result.decode(bodyType)); } @Override @@ -375,7 +368,6 @@ class DefaultWebTestClient implements WebTestClient { public FluxExchangeResult returnResult(ResolvableType elementType) { return this.result.decodeToFlux(elementType); } - } @@ -383,26 +375,23 @@ class DefaultWebTestClient implements WebTestClient { private final EntityExchangeResult result; - DefaultBodySpec(EntityExchangeResult result) { this.result = result; } - protected EntityExchangeResult getResult() { return this.result; } @Override public T isEqualTo(B expected) { - B actual = this.result.getResponseBody(); - this.result.assertWithDiagnostics(() -> assertEquals("Response body", expected, actual)); + this.result.assertWithDiagnostics(() -> + assertEquals("Response body", expected, this.result.getResponseBody())); return self(); } @Override public T consumeWith(Consumer> consumer) { - B actual = this.result.getResponseBody(); this.result.assertWithDiagnostics(() -> consumer.accept(this.result)); return self(); } @@ -416,24 +405,21 @@ class DefaultWebTestClient implements WebTestClient { public EntityExchangeResult returnResult() { return this.result; } - } private static class DefaultListBodySpec extends DefaultBodySpec, ListBodySpec> implements ListBodySpec { - DefaultListBodySpec(EntityExchangeResult> result) { super(result); } - @Override public ListBodySpec hasSize(int size) { List actual = getResult().getResponseBody(); String message = "Response body does not contain " + size + " elements"; - getResult().assertWithDiagnostics(() -> assertEquals(message, size, actual.size())); + getResult().assertWithDiagnostics(() -> assertEquals(message, size, (actual != null ? actual.size() : 0))); return this; } @@ -443,7 +429,7 @@ class DefaultWebTestClient implements WebTestClient { List expected = Arrays.asList(elements); List actual = getResult().getResponseBody(); String message = "Response body does not contain " + expected; - getResult().assertWithDiagnostics(() -> assertTrue(message, actual.containsAll(expected))); + getResult().assertWithDiagnostics(() -> assertTrue(message, (actual != null && actual.containsAll(expected)))); return this; } @@ -452,8 +438,8 @@ class DefaultWebTestClient implements WebTestClient { public ListBodySpec doesNotContain(E... elements) { List expected = Arrays.asList(elements); List actual = getResult().getResponseBody(); - String message = "Response body should have contained " + expected; - getResult().assertWithDiagnostics(() -> assertTrue(message, !actual.containsAll(expected))); + String message = "Response body should not have contained " + expected; + getResult().assertWithDiagnostics(() -> assertTrue(message, (actual == null || !actual.containsAll(expected)))); return this; } @@ -461,7 +447,6 @@ class DefaultWebTestClient implements WebTestClient { public EntityExchangeResult> returnResult() { return getResult(); } - } @@ -471,13 +456,11 @@ class DefaultWebTestClient implements WebTestClient { private final boolean isEmpty; - DefaultBodyContentSpec(EntityExchangeResult result) { this.result = result; this.isEmpty = (result.getResponseBody() == null); } - @Override public EntityExchangeResult isEmpty() { this.result.assertWithDiagnostics(() -> assertTrue("Expected empty body", this.isEmpty)); @@ -502,14 +485,14 @@ class DefaultWebTestClient implements WebTestClient { return new JsonPathAssertions(this, getBodyAsString(), expression, args); } - @Nullable private String getBodyAsString() { - if (this.isEmpty) { - return null; + byte[] body = this.result.getResponseBody(); + if (body == null || body.length == 0) { + return ""; } MediaType mediaType = this.result.getResponseHeaders().getContentType(); Charset charset = Optional.ofNullable(mediaType).map(MimeType::getCharset).orElse(UTF_8); - return new String(this.result.getResponseBody(), charset); + return new String(body, charset); } @Override @@ -522,7 +505,6 @@ class DefaultWebTestClient implements WebTestClient { public EntityExchangeResult returnResult() { return this.result; } - } } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/EntityExchangeResult.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/EntityExchangeResult.java index 767c89394c..a29c55d9f2 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/EntityExchangeResult.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/EntityExchangeResult.java @@ -16,6 +16,8 @@ package org.springframework.test.web.reactive.server; +import org.springframework.lang.Nullable; + /** * {@code ExchangeResult} sub-class that exposes the response body fully * extracted to a representation of type {@code }. @@ -30,7 +32,7 @@ public class EntityExchangeResult extends ExchangeResult { private final T body; - EntityExchangeResult(ExchangeResult result, T body) { + EntityExchangeResult(ExchangeResult result, @Nullable T body) { super(result); this.body = body; } @@ -39,6 +41,7 @@ public class EntityExchangeResult extends ExchangeResult { /** * Return the entity extracted from the response body. */ + @Nullable public T getResponseBody() { return this.body; } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java index a19299736a..1f6bf9b55c 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java @@ -31,6 +31,7 @@ import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseCookie; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; @@ -110,6 +111,7 @@ public class ExchangeResult { /** * Return the original URI template used to prepare the request, if any. */ + @Nullable public String getUriTemplate() { return this.uriTemplate; } @@ -194,11 +196,7 @@ public class ExchangeResult { } private String getStatusReason() { - String reason = ""; - if (getStatus() != null && getStatus().getReasonPhrase() != null) { - reason = getStatus().getReasonPhrase(); - } - return reason; + return getStatus().getReasonPhrase(); } private String formatHeaders(HttpHeaders headers, String delimiter) { @@ -207,7 +205,7 @@ public class ExchangeResult { .collect(Collectors.joining(delimiter)); } - private String formatBody(MediaType contentType, MonoProcessor body) { + private String formatBody(@Nullable MediaType contentType, MonoProcessor body) { if (body.isSuccess()) { byte[] bytes = body.block(Duration.ZERO); if (bytes.length == 0) { diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java index 4088c6a741..f49a6a7c8e 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java @@ -23,9 +23,9 @@ import org.springframework.http.CacheControl; import org.springframework.http.ContentDisposition; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; -import static org.springframework.test.util.AssertionErrors.assertEquals; -import static org.springframework.test.util.AssertionErrors.assertTrue; +import static org.springframework.test.util.AssertionErrors.*; /** * Assertions on headers of the response. @@ -62,7 +62,9 @@ public class HeaderAssertions { */ public WebTestClient.ResponseSpec valueMatches(String name, String pattern) { String value = getHeaders().getFirst(name); - assertTrue(getMessage(name) + " not found", value != null); + if (value == null) { + fail(getMessage(name) + " not found"); + } boolean match = Pattern.compile(pattern).matcher(value).matches(); String message = getMessage(name) + "=\'" + value + "\' does not match \'" + pattern + "\'"; this.exchangeResult.assertWithDiagnostics(() -> assertTrue(message, match)); @@ -122,7 +124,7 @@ public class HeaderAssertions { return "Response header [" + headerName + "]"; } - private WebTestClient.ResponseSpec assertHeader(String name, Object expected, Object actual) { + private WebTestClient.ResponseSpec assertHeader(String name, @Nullable Object expected, @Nullable Object actual) { this.exchangeResult.assertWithDiagnostics(() -> assertEquals(getMessage(name), expected, actual)); return this.responseSpec; } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java index b4eaa2e97e..accd3a3017 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.test.web.reactive.server; import org.springframework.test.util.JsonPathExpectationsHelper; - /** *
JsonPath assertions. * diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/DefaultMvcResult.java b/spring-test/src/main/java/org/springframework/test/web/servlet/DefaultMvcResult.java index 87a7927821..ec16470112 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/DefaultMvcResult.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/DefaultMvcResult.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.test.web.servlet; import java.util.concurrent.atomic.AtomicReference; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.web.servlet.FlashMap; @@ -71,7 +72,7 @@ class DefaultMvcResult implements MvcResult { return this.mockResponse; } - public void setHandler(Object handler) { + public void setHandler(@Nullable Object handler) { this.handler = handler; } @@ -80,7 +81,7 @@ class DefaultMvcResult implements MvcResult { return this.handler; } - public void setInterceptors(HandlerInterceptor... interceptors) { + public void setInterceptors(@Nullable HandlerInterceptor... interceptors) { this.interceptors = interceptors; } @@ -98,7 +99,7 @@ class DefaultMvcResult implements MvcResult { return this.resolvedException; } - public void setModelAndView(ModelAndView mav) { + public void setModelAndView(@Nullable ModelAndView mav) { this.modelAndView = mav; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java index 97c4e84d2a..ccd719477a 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,18 +79,16 @@ public final class MockMvc { * Private constructor, not for direct instantiation. * @see org.springframework.test.web.servlet.setup.MockMvcBuilders */ - MockMvc(TestDispatcherServlet servlet, Filter[] filters, ServletContext servletContext) { - + MockMvc(TestDispatcherServlet servlet, Filter... filters) { Assert.notNull(servlet, "DispatcherServlet is required"); - Assert.notNull(filters, "filters cannot be null"); - Assert.noNullElements(filters, "filters cannot contain null values"); - Assert.notNull(servletContext, "A ServletContext is required"); - + Assert.notNull(filters, "Filters cannot be null"); + Assert.noNullElements(filters, "Filters cannot contain null values"); this.servlet = servlet; this.filters = filters; - this.servletContext = servletContext; + this.servletContext = servlet.getServletContext(); } + /** * A default request builder merged into every performed request. * @see org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder#defaultRequest(RequestBuilder) @@ -120,18 +118,14 @@ public final class MockMvc { /** * Perform a request and return a type that allows chaining further * actions, such as asserting expectations, on the result. - * * @param requestBuilder used to prepare the request to execute; * see static factory methods in * {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders} - * * @return an instance of {@link ResultActions}; never {@code null} - * * @see org.springframework.test.web.servlet.request.MockMvcRequestBuilders * @see org.springframework.test.web.servlet.result.MockMvcResultMatchers */ public ResultActions perform(RequestBuilder requestBuilder) throws Exception { - if (this.defaultRequestBuilder != null) { if (requestBuilder instanceof Mergeable) { requestBuilder = (RequestBuilder) ((Mergeable) requestBuilder).merge(this.defaultRequestBuilder); @@ -156,28 +150,23 @@ public final class MockMvc { if (DispatcherType.ASYNC.equals(request.getDispatcherType()) && request.getAsyncContext() != null & !request.isAsyncStarted()) { - request.getAsyncContext().complete(); } applyDefaultResultActions(mvcResult); - RequestContextHolder.setRequestAttributes(previousAttributes); return new ResultActions() { - @Override public ResultActions andExpect(ResultMatcher matcher) throws Exception { matcher.match(mvcResult); return this; } - @Override public ResultActions andDo(ResultHandler handler) throws Exception { handler.handle(mvcResult); return this; } - @Override public MvcResult andReturn() { return mvcResult; @@ -185,6 +174,7 @@ public final class MockMvc { }; } + private void applyDefaultResultActions(MvcResult mvcResult) throws Exception { for (ResultMatcher matcher : this.defaultResultMatchers) { diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java index db7c4a2984..01773787bc 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,10 @@ package org.springframework.test.web.servlet; import java.util.List; import javax.servlet.Filter; -import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.springframework.core.NestedRuntimeException; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockServletConfig; import org.springframework.web.context.WebApplicationContext; @@ -43,9 +43,7 @@ public abstract class MockMvcBuilderSupport { protected final MockMvc createMockMvc(Filter[] filters, MockServletConfig servletConfig, WebApplicationContext webAppContext, RequestBuilder defaultRequestBuilder, List globalResultMatchers, List globalResultHandlers, - List dispatcherServletCustomizers) { - - ServletContext servletContext = webAppContext.getServletContext(); + @Nullable List dispatcherServletCustomizers) { TestDispatcherServlet dispatcherServlet = new TestDispatcherServlet(webAppContext); if (dispatcherServletCustomizers != null) { @@ -61,7 +59,7 @@ public abstract class MockMvcBuilderSupport { throw new MockMvcBuildException("Failed to initialize TestDispatcherServlet", ex); } - MockMvc mockMvc = new MockMvc(dispatcherServlet, filters, servletContext); + MockMvc mockMvc = new MockMvc(dispatcherServlet, filters); mockMvc.setDefaultRequest(defaultRequestBuilder); mockMvc.setGlobalResultMatchers(globalResultMatchers); mockMvc.setGlobalResultHandlers(globalResultHandlers); @@ -69,6 +67,7 @@ public abstract class MockMvcBuilderSupport { return mockMvc; } + @SuppressWarnings("serial") private static class MockMvcBuildException extends NestedRuntimeException { diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/MvcResult.java b/spring-test/src/main/java/org/springframework/test/web/servlet/MvcResult.java index 24f0820385..05892882f9 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/MvcResult.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/MvcResult.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License; Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,7 +60,7 @@ public interface MvcResult { /** * Return the {@code ModelAndView} prepared by the handler. - * @return a {@code ModelAndView}, or {@code null} + * @return a {@code ModelAndView}, or {@code null} if none */ @Nullable ModelAndView getModelAndView(); @@ -68,7 +68,7 @@ public interface MvcResult { /** * Return any exception raised by a handler and successfully resolved * through a {@link HandlerExceptionResolver}. - * @return an exception, possibly {@code null} + * @return an exception, or {@code null} if none */ @Nullable Exception getResolvedException(); diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/RequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/RequestBuilder.java index c3f02ee2f3..c735da0455 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/RequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/RequestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,6 @@ public interface RequestBuilder { /** * Build the request. - * * @param servletContext the {@link ServletContext} to use to create the request * @return the request */ diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java index 74eaf8a222..5ea6305b29 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java @@ -107,11 +107,13 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { Charset charset = getCharset(); String httpMethod = this.webRequest.getHttpMethod().name(); UriComponents uriComponents = uriComponents(); + String path = uriComponents.getPath(); MockHttpServletRequest request = new HtmlUnitMockHttpServletRequest( - servletContext, httpMethod, uriComponents.getPath()); + servletContext, httpMethod, (path != null ? path : "")); parent(request, this.parentBuilder); - request.setServerName(uriComponents.getHost()); // needs to be first for additional headers + String host = uriComponents.getHost(); + request.setServerName(host != null ? host : ""); // needs to be first for additional headers authType(request); request.setCharacterEncoding(charset.name()); content(request, charset); @@ -125,7 +127,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { ports(uriComponents, request); request.setProtocol("HTTP/1.1"); request.setQueryString(uriComponents.getQuery()); - request.setScheme(uriComponents.getScheme()); + String scheme = uriComponents.getScheme(); + request.setScheme(scheme != null ? scheme : ""); request.setPathInfo(null); return postProcess(request); @@ -146,7 +149,7 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { return request; } - private void parent(MockHttpServletRequest request, RequestBuilder parent) { + private void parent(MockHttpServletRequest request, @Nullable RequestBuilder parent) { if (parent == null) { return; } @@ -156,11 +159,13 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { // session HttpSession parentSession = parentRequest.getSession(false); if (parentSession != null) { + HttpSession localSession = request.getSession(); + Assert.state(localSession != null, "No local HttpSession"); Enumeration attrNames = parentSession.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = attrNames.nextElement(); Object attrValue = parentSession.getAttribute(attrName); - request.getSession().setAttribute(attrName, attrValue); + localSession.setAttribute(attrName, attrValue); } } @@ -254,7 +259,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { } } else { - Assert.isTrue(uriComponents.getPath().startsWith(this.contextPath), + String path = uriComponents.getPath(); + Assert.isTrue(path != null && path.startsWith(this.contextPath), () -> "\"" + uriComponents.getPath() + "\" should start with context path \"" + this.contextPath + "\""); request.setContextPath(this.contextPath); @@ -302,6 +308,7 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { } } + @Nullable private String header(String headerName) { return this.webRequest.getAdditionalHeaders().get(headerName); } @@ -376,9 +383,6 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { private void servletPath(MockHttpServletRequest request, String requestPath) { String servletPath = requestPath.substring(request.getContextPath().length()); - if ("".equals(servletPath)) { - servletPath = null; - } request.setServletPath(servletPath); } @@ -386,7 +390,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { if ("".equals(request.getPathInfo())) { request.setPathInfo(null); } - servletPath(request, uriComponents.getPath()); + String path = uriComponents.getPath(); + servletPath(request, (path != null ? path : "")); } private void ports(UriComponents uriComponents, MockHttpServletRequest request) { diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnection.java b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnection.java index 657f1546d5..4a4ea2c97d 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnection.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnection.java @@ -154,9 +154,6 @@ public final class MockMvcWebConnection implements WebConnection { } private void storeCookies(WebRequest webRequest, javax.servlet.http.Cookie[] cookies) { - if (cookies == null) { - return; - } Date now = new Date(); CookieManager cookieManager = this.webClient.getCookieManager(); for (javax.servlet.http.Cookie cookie : cookies) { diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java index 0a0e056ce1..c7938e6f68 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java @@ -30,10 +30,10 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; - import javax.servlet.ServletContext; import javax.servlet.ServletRequest; import javax.servlet.http.Cookie; +import javax.servlet.http.HttpSession; import org.springframework.beans.Mergeable; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -173,7 +173,7 @@ public class MockHttpServletRequestBuilder Assert.isTrue(contextPath.startsWith("/"), "Context path must start with a '/'"); Assert.isTrue(!contextPath.endsWith("/"), "Context path must not end with a '/'"); } - this.contextPath = (contextPath != null ? contextPath : ""); + this.contextPath = contextPath; return this; } @@ -195,7 +195,7 @@ public class MockHttpServletRequestBuilder Assert.isTrue(servletPath.startsWith("/"), "Servlet path must start with a '/'"); Assert.isTrue(!servletPath.endsWith("/"), "Servlet path must not end with a '/'"); } - this.servletPath = (servletPath != null ? servletPath : ""); + this.servletPath = servletPath; return this; } @@ -311,9 +311,8 @@ public class MockHttpServletRequestBuilder * @param httpHeaders the headers and values to add */ public MockHttpServletRequestBuilder headers(HttpHeaders httpHeaders) { - for (String name : httpHeaders.keySet()) { - Object[] values = ObjectUtils.toObjectArray(httpHeaders.get(name).toArray()); - addToMultiValueMap(this.headers, name, values); + for (Map.Entry> entry : httpHeaders.entrySet()) { + this.headers.addAll(entry.getKey(), entry.getValue()); } return this; } @@ -654,7 +653,9 @@ public class MockHttpServletRequestBuilder request.setAttribute(name, this.requestAttributes.get(name)); } for (String name : this.sessionAttributes.keySet()) { - request.getSession().setAttribute(name, this.sessionAttributes.get(name)); + HttpSession session = request.getSession(); + Assert.state(session != null, "No HttpSession"); + session.setAttribute(name, this.sessionAttributes.get(name)); } FlashMap flashMap = new FlashMap(); @@ -739,10 +740,7 @@ public class MockHttpServletRequestBuilder WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); flashMapManager = wac.getBean(DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class); } - catch (IllegalStateException ex) { - // ignore - } - catch (NoSuchBeanDefinitionException ex) { + catch (IllegalStateException | NoSuchBeanDefinitionException ex) { // ignore } return (flashMapManager != null ? flashMapManager : new SessionFlashMapManager()); @@ -752,8 +750,6 @@ public class MockHttpServletRequestBuilder public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { for (RequestPostProcessor postProcessor : this.postProcessors) { request = postProcessor.postProcessRequest(request); - Assert.state(request != null, - () -> "Post-processor [" + postProcessor.getClass().getName() + "] returned null"); } return request; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java index 361cea0ac1..9d5a5fbe68 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java @@ -77,7 +77,9 @@ public class ContentResultMatchers { return result -> { String actual = result.getResponse().getContentType(); assertTrue("Content type not set", actual != null); - assertEquals("Content type", contentType, MediaType.parseMediaType(actual)); + if (actual != null) { + assertEquals("Content type", contentType, MediaType.parseMediaType(actual)); + } }; } @@ -97,9 +99,11 @@ public class ContentResultMatchers { return result -> { String actual = result.getResponse().getContentType(); assertTrue("Content type not set", actual != null); - MediaType actualContentType = MediaType.parseMediaType(actual); - assertTrue("Content type [" + actual + "] is not compatible with [" + contentType + "]", - actualContentType.isCompatibleWith(contentType)); + if (actual != null) { + MediaType actualContentType = MediaType.parseMediaType(actual); + assertTrue("Content type [" + actual + "] is not compatible with [" + contentType + "]", + actualContentType.isCompatibleWith(contentType)); + } }; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/CookieResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/CookieResultMatchers.java index 0adda19b2c..f5bb9357e3 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/CookieResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/CookieResultMatchers.java @@ -20,6 +20,7 @@ import javax.servlet.http.Cookie; import org.hamcrest.Matcher; +import org.springframework.test.util.AssertionErrors; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultMatcher; @@ -206,7 +207,9 @@ public class CookieResultMatchers { private static Cookie getCookie(MvcResult result, String name) { Cookie cookie = result.getResponse().getCookie(name); - assertTrue("No cookie with name '" + name + "'", cookie != null); + if (cookie == null) { + AssertionErrors.fail("No cookie with name '" + name + "'"); + } return cookie; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/HandlerResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/HandlerResultMatchers.java index 3660281509..c6d8407441 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/HandlerResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/HandlerResultMatchers.java @@ -64,11 +64,13 @@ public class HandlerResultMatchers { return result -> { Object handler = result.getHandler(); assertTrue("No handler", handler != null); - Class actual = handler.getClass(); - if (HandlerMethod.class.isInstance(handler)) { - actual = ((HandlerMethod) handler).getBeanType(); + if (handler != null) { + Class actual = handler.getClass(); + if (HandlerMethod.class.isInstance(handler)) { + actual = ((HandlerMethod) handler).getBeanType(); + } + assertEquals("Handler type", type, ClassUtils.getUserClass(actual)); } - assertEquals("Handler type", type, ClassUtils.getUserClass(actual)); }; } @@ -145,7 +147,9 @@ public class HandlerResultMatchers { private static HandlerMethod getHandlerMethod(MvcResult result) { Object handler = result.getHandler(); assertTrue("No handler", handler != null); - assertTrue("Not a HandlerMethod: " + handler, handler instanceof HandlerMethod); + if (!(handler instanceof HandlerMethod)) { + fail("Not a HandlerMethod: " + handler); + } return (HandlerMethod) handler; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java index 02ef34a9f3..593a889842 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java @@ -109,7 +109,10 @@ public class HeaderResultMatchers { return result -> { MockHttpServletResponse response = result.getResponse(); assertTrue("Response does not contain header '" + name + "'", response.containsHeader(name)); - assertEquals("Response header '" + name + "'", value, Long.parseLong(response.getHeader(name))); + String headerValue = response.getHeader(name); + if (headerValue != null) { + assertEquals("Response header '" + name + "'", value, Long.parseLong(headerValue)); + } }; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultHandlers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultHandlers.java index 8f13a05df9..690cba33e1 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultHandlers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultHandlers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.io.Writer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.lang.Nullable; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultHandler; import org.springframework.util.CollectionUtils; @@ -104,7 +105,7 @@ public abstract class MockMvcResultHandlers { writer.println(String.format("%s:", heading)); } @Override - public void printValue(String label, Object value) { + public void printValue(String label, @Nullable Object value) { if (value != null && value.getClass().isArray()) { value = CollectionUtils.arrayToList(value); } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java index 66caf58029..49d4205064 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -102,8 +102,9 @@ public abstract class MockMvcResultMatchers { public static ResultMatcher forwardedUrlPattern(String urlPattern) { return result -> { assertTrue("AntPath pattern", pathMatcher.isPattern(urlPattern)); + String url = result.getResponse().getForwardedUrl(); assertTrue("Forwarded URL does not match the expected URL pattern", - pathMatcher.match(urlPattern, result.getResponse().getForwardedUrl())); + (url != null && pathMatcher.match(urlPattern, url))); }; } @@ -129,9 +130,10 @@ public abstract class MockMvcResultMatchers { */ public static ResultMatcher redirectedUrlPattern(String urlPattern) { return result -> { - assertTrue("AntPath pattern", pathMatcher.isPattern(urlPattern)); + assertTrue("No Ant-style path pattern", pathMatcher.isPattern(urlPattern)); + String url = result.getResponse().getRedirectedUrl(); assertTrue("Redirected URL does not match the expected URL pattern", - pathMatcher.match(urlPattern, result.getResponse().getRedirectedUrl())); + (url != null && pathMatcher.match(urlPattern, url))); }; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ModelResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ModelResultMatchers.java index 565f00d1c2..2053017c84 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ModelResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ModelResultMatchers.java @@ -23,6 +23,7 @@ import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; import org.springframework.web.servlet.ModelAndView; import static org.hamcrest.MatcherAssert.*; @@ -155,10 +156,12 @@ public class ModelResultMatchers { ModelAndView mav = getModelAndView(mvcResult); BindingResult result = getBindingResult(mav, name); assertTrue("No errors for attribute '" + name + "'", result.hasErrors()); - boolean hasFieldErrors = result.hasFieldErrors(fieldName); - assertTrue("No errors for field '" + fieldName + "' of attribute '" + name + "'", hasFieldErrors); - String code = result.getFieldError(fieldName).getCode(); - assertTrue("Expected error code '" + error + "' but got '" + code + "'", code.equals(error)); + FieldError fieldError = result.getFieldError(fieldName); + if (fieldError == null) { + fail("No errors for field '" + fieldName + "' of attribute '" + name + "'"); + } + String code = fieldError.getCode(); + assertTrue("Expected error code '" + error + "' but got '" + code + "'", error.equals(code)); }; } @@ -173,9 +176,11 @@ public class ModelResultMatchers { ModelAndView mav = getModelAndView(mvcResult); BindingResult result = getBindingResult(mav, name); assertTrue("No errors for attribute: [" + name + "]", result.hasErrors()); - boolean hasFieldErrors = result.hasFieldErrors(fieldName); - assertTrue("No errors for field '" + fieldName + "' of attribute '" + name + "'", hasFieldErrors); - String code = result.getFieldError(fieldName).getCode(); + FieldError fieldError = result.getFieldError(fieldName); + if (fieldError == null) { + fail("No errors for field '" + fieldName + "' of attribute '" + name + "'"); + } + String code = fieldError.getCode(); assertThat("Field name '" + fieldName + "' of attribute '" + name + "'", code, matcher); }; } @@ -232,13 +237,17 @@ public class ModelResultMatchers { private ModelAndView getModelAndView(MvcResult mvcResult) { ModelAndView mav = mvcResult.getModelAndView(); - assertTrue("No ModelAndView found", mav != null); + if (mav == null) { + fail("No ModelAndView found"); + }; return mav; } private BindingResult getBindingResult(ModelAndView mav, String name) { BindingResult result = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + name); - assertTrue("No BindingResult for attribute: " + name, result != null); + if (result == null) { + fail("No BindingResult for attribute: " + name); + } return result; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java index b7cea04a84..d7e9954beb 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java @@ -26,6 +26,7 @@ import javax.servlet.http.HttpSession; import org.springframework.core.style.ToStringCreator; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.web.servlet.MvcResult; @@ -168,7 +169,7 @@ public class PrintingResultHandler implements ResultHandler { /** * Print the handler. */ - protected void printHandler(Object handler, HandlerInterceptor[] interceptors) throws Exception { + protected void printHandler(@Nullable Object handler, @Nullable HandlerInterceptor[] interceptors) throws Exception { if (handler == null) { this.printer.printValue("Type", null); } @@ -187,7 +188,7 @@ public class PrintingResultHandler implements ResultHandler { /** * Print exceptions resolved through a HandlerExceptionResolver. */ - protected void printResolvedException(Exception resolvedException) throws Exception { + protected void printResolvedException(@Nullable Exception resolvedException) throws Exception { if (resolvedException == null) { this.printer.printValue("Type", null); } @@ -199,7 +200,7 @@ public class PrintingResultHandler implements ResultHandler { /** * Print the ModelAndView. */ - protected void printModelAndView(ModelAndView mav) throws Exception { + protected void printModelAndView(@Nullable ModelAndView mav) throws Exception { this.printer.printValue("View name", (mav != null) ? mav.getViewName() : null); this.printer.printValue("View", (mav != null) ? mav.getView() : null); if (mav == null || mav.getModel().size() == 0) { @@ -292,7 +293,7 @@ public class PrintingResultHandler implements ResultHandler { void printHeading(String heading); - void printValue(String label, Object value); + void printValue(String label, @Nullable Object value); } } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/RequestResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/RequestResultMatchers.java index b16f818798..874ed78596 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/RequestResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/RequestResultMatchers.java @@ -18,11 +18,13 @@ package org.springframework.test.web.servlet.result; import java.util.concurrent.Callable; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import org.hamcrest.Matcher; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.web.servlet.ResultMatcher; +import org.springframework.util.Assert; import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.context.request.async.WebAsyncTask; @@ -129,7 +131,9 @@ public class RequestResultMatchers { @SuppressWarnings("unchecked") public ResultMatcher sessionAttribute(final String name, final Matcher matcher) { return result -> { - T value = (T) result.getRequest().getSession().getAttribute(name); + HttpSession session = result.getRequest().getSession(); + Assert.state(session != null, "No HttpSession"); + T value = (T) session.getAttribute(name); assertThat("Session attribute '" + name + "'", value, matcher); }; } @@ -139,8 +143,11 @@ public class RequestResultMatchers { */ @SuppressWarnings("unchecked") public ResultMatcher sessionAttribute(final String name, final Object value) { - return result -> - assertEquals("Session attribute '" + name + "'", value, result.getRequest().getSession().getAttribute(name)); + return result -> { + HttpSession session = result.getRequest().getSession(); + Assert.state(session != null, "No HttpSession"); + assertEquals("Session attribute '" + name + "'", value, session.getAttribute(name)); + }; } private static void assertAsyncStarted(HttpServletRequest request) { diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ViewResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ViewResultMatchers.java index 7b7d57dfb1..d2069e4848 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ViewResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ViewResultMatchers.java @@ -49,7 +49,9 @@ public class ViewResultMatchers { public ResultMatcher name(final Matcher matcher) { return result -> { ModelAndView mav = result.getModelAndView(); - assertTrue("No ModelAndView found", mav != null); + if (mav == null) { + fail("No ModelAndView found"); + } assertThat("View name", mav.getViewName(), matcher); }; } @@ -60,7 +62,9 @@ public class ViewResultMatchers { public ResultMatcher name(final String expectedViewName) { return result -> { ModelAndView mav = result.getModelAndView(); - assertTrue("No ModelAndView found", mav != null); + if (mav == null) { + fail("No ModelAndView found"); + } assertEquals("View name", expectedViewName, mav.getViewName()); }; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/XpathResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/XpathResultMatchers.java index 77e32928b2..4d34e0ef45 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/XpathResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/XpathResultMatchers.java @@ -17,7 +17,6 @@ package org.springframework.test.web.servlet.result; import java.util.Map; - import javax.xml.xpath.XPathExpressionException; import org.hamcrest.Matcher; @@ -72,8 +71,9 @@ public class XpathResultMatchers { /** * Get the response encoding if explicitly defined in the response, {code null} otherwise. */ + @Nullable private String getDefinedEncoding(MockHttpServletResponse response) { - return response.isCharset() ? response.getCharacterEncoding() : null; + return (response.isCharset() ? response.getCharacterEncoding() : null); } /** diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java index a20674b007..437f27c8d9 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java @@ -40,7 +40,7 @@ import org.springframework.test.web.servlet.MockMvcBuilder; * configuring filters, default request properties, global expectations and * global result actions. * - *

Sub-classes can use different strategies to prepare the Spring + *

Subclasses can use different strategies to prepare the Spring * {@code WebApplicationContext} that will be passed to the * {@code DispatcherServlet}. * @@ -126,9 +126,7 @@ public abstract class AbstractMockMvcBuilder @Override @SuppressWarnings("rawtypes") public final MockMvc build() { - WebApplicationContext wac = initWebAppContext(); - ServletContext servletContext = wac.getServletContext(); MockServletConfig mockServletConfig = new MockServletConfig(servletContext); diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/ConfigurableMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/ConfigurableMockMvcBuilder.java index 908dec126d..e97c84d998 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/ConfigurableMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/ConfigurableMockMvcBuilder.java @@ -29,49 +29,38 @@ import org.springframework.test.web.servlet.ResultMatcher; * @author Rossen Stoyanchev * @since 4.1 */ -public interface ConfigurableMockMvcBuilder> - extends MockMvcBuilder { +public interface ConfigurableMockMvcBuilder> extends MockMvcBuilder { /** * Add filters mapped to any request (i.e. "/*"). For example: - * *

 	 * mockMvcBuilder.addFilters(springSecurityFilterChain);
 	 * 
- * *

is the equivalent of the following web.xml configuration: - * *

 	 * <filter-mapping>
 	 *     <filter-name>springSecurityFilterChain</filter-name>
 	 *     <url-pattern>/*</url-pattern>
 	 * </filter-mapping>
 	 * 
- * *

Filters will be invoked in the order in which they are provided. - * * @param filters the filters to add */ T addFilters(Filter... filters); /** * Add a filter mapped to a specific set of patterns. For example: - * *

 	 * mockMvcBuilder.addFilters(myResourceFilter, "/resources/*");
 	 * 
- * *

is the equivalent of: - * *

 	 * <filter-mapping>
 	 *     <filter-name>myResourceFilter</filter-name>
 	 *     <url-pattern>/resources/*</url-pattern>
 	 * </filter-mapping>
 	 * 
- * *

Filters will be invoked in the order in which they are provided. - * * @param filter the filter to add * @param urlPatterns URL patterns to map to; if empty, "/*" is used by default */ @@ -85,10 +74,8 @@ public interface ConfigurableMockMvcBuilderProperties specified at the time of performing a request override the * default properties defined here. - * * @param requestBuilder a RequestBuilder; see static factory methods in * {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders} - * . */ T defaultRequest(RequestBuilder requestBuilder); @@ -96,7 +83,6 @@ public interface ConfigurableMockMvcBuilderalways be applied to * every response. For example, status code 200 (OK), content type * {@code "application/json"}, etc. - * * @param resultMatcher a ResultMatcher; see static factory methods in * {@link org.springframework.test.web.servlet.result.MockMvcResultMatchers} */ @@ -106,7 +92,6 @@ public interface ConfigurableMockMvcBuilderalways be applied to every * response. For example, writing detailed information about the performed * request and resulting response to {@code System.out}. - * * @param resultHandler a ResultHandler; see static factory methods in * {@link org.springframework.test.web.servlet.result.MockMvcResultHandlers} */ @@ -122,12 +107,10 @@ public interface ConfigurableMockMvcBuilderThere is a built-in {@link SharedHttpSessionConfigurer} that can be * used to re-use the HTTP session across requests. 3rd party frameworks * like Spring Security also use this mechanism to provide configuration * shortcuts. - * * @see SharedHttpSessionConfigurer */ T apply(MockMvcConfigurer configurer); diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java index 4d5e7c012b..8affcdbb0b 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,10 +54,11 @@ public class DefaultMockMvcBuilder extends AbstractMockMvcBuilder builder); + default void afterConfigurerAdded(ConfigurableMockMvcBuilder builder) { + } /** * Invoked when the MockMvc instance is about to be created with the MockMvc @@ -58,7 +60,11 @@ public interface MockMvcConfigurer { * @return a post processor to be applied to every request performed * through the {@code MockMvc} instance. */ - RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder builder, - WebApplicationContext context); + @Nullable + default RequestPostProcessor beforeMockMvcCreated( + ConfigurableMockMvcBuilder builder, WebApplicationContext context) { + + return null; + } } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java index ef9e5f1c34..06b5fbd1ff 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.function.Supplier; +import javax.servlet.ServletContext; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanInitializationException; @@ -32,6 +33,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockServletContext; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -190,7 +192,9 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder>> initializerClasses1 = + Set>> initializerClasses1 = new HashSet<>(); initializerClasses1.add(FooInitializer.class); initializerClasses1.add(BarInitializer.class); - Set>> initializerClasses2 = + Set>> initializerClasses2 = new HashSet<>(); initializerClasses2.add(BarInitializer.class); initializerClasses2.add(FooInitializer.class); @@ -190,11 +190,11 @@ public class MergedContextConfigurationTests { @Test public void hashCodeWithDifferentInitializers() { - Set>> initializerClasses1 = + Set>> initializerClasses1 = new HashSet<>(); initializerClasses1.add(FooInitializer.class); - Set>> initializerClasses2 = + Set>> initializerClasses2 = new HashSet<>(); initializerClasses2.add(BarInitializer.class); @@ -368,12 +368,12 @@ public class MergedContextConfigurationTests { @Test public void equalsWithSameInitializers() { - Set>> initializerClasses1 = + Set>> initializerClasses1 = new HashSet<>(); initializerClasses1.add(FooInitializer.class); initializerClasses1.add(BarInitializer.class); - Set>> initializerClasses2 = + Set>> initializerClasses2 = new HashSet<>(); initializerClasses2.add(BarInitializer.class); initializerClasses2.add(FooInitializer.class); @@ -387,11 +387,11 @@ public class MergedContextConfigurationTests { @Test public void equalsWithDifferentInitializers() { - Set>> initializerClasses1 = + Set>> initializerClasses1 = new HashSet<>(); initializerClasses1.add(FooInitializer.class); - Set>> initializerClasses2 = + Set>> initializerClasses2 = new HashSet<>(); initializerClasses2.add(BarInitializer.class); diff --git a/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java b/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java index 5782739126..a736ae7a0f 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/AbstractContextConfigurationUtilsTests.java @@ -54,8 +54,8 @@ abstract class AbstractContextConfigurationUtilsTests { static final String[] EMPTY_STRING_ARRAY = new String[0]; - static final Set>> - EMPTY_INITIALIZER_CLASSES = Collections.>> emptySet(); + static final Set>> + EMPTY_INITIALIZER_CLASSES = Collections.>> emptySet(); MergedContextConfiguration buildMergedContextConfiguration(Class testClass) { @@ -89,7 +89,7 @@ abstract class AbstractContextConfigurationUtilsTests { Class expectedTestClass, String[] expectedLocations, Class[] expectedClasses, - Set>> expectedInitializerClasses, + Set>> expectedInitializerClasses, Class expectedContextLoaderClass) { assertNotNull(mergedConfig); diff --git a/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java b/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java index 6be602776f..44ec44f936 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/ActiveProfilesUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -205,9 +205,8 @@ public class ActiveProfilesUtilsTests extends AbstractContextConfigurationUtilsT /** * @since 4.0 */ - @Test(expected = IllegalStateException.class) public void resolveActiveProfilesWithResolverThatReturnsNull() { - resolveActiveProfiles(NullActiveProfilesResolverTestCase.class); + assertResolvedProfiles(NullActiveProfilesResolverTestCase.class); } /** diff --git a/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java b/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java index f92c74183a..452827fcc8 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java @@ -84,8 +84,8 @@ public class BootstrapTestUtilsContextInitializerTests extends AbstractContextCo initializers(BarInitializer.class), DelegatingSmartContextLoader.class); } - private Set>> initializers( - Class>... classes) { + private Set>> initializers( + Class>... classes) { return new HashSet<>(Arrays.asList(classes)); } diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionTests.java index fd23670654..3760034206 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import java.io.IOException; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; -import org.junit.Before; import org.junit.Test; import org.springframework.test.web.servlet.MockMvc; @@ -39,47 +38,35 @@ public class MockMvcWebConnectionTests { private final WebClient webClient = new WebClient(); - private MockMvc mockMvc; + private final MockMvc mockMvc = + MockMvcBuilders.standaloneSetup(new HelloController(), new ForwardController()).build(); - @Before - public void setup() { - this.mockMvc = MockMvcBuilders.standaloneSetup(new HelloController(), new ForwardController()).build(); - } - @Test public void contextPathNull() throws IOException { this.webClient.setWebConnection(new MockMvcWebConnection(this.mockMvc, this.webClient)); - Page page = this.webClient.getPage("http://localhost/context/a"); - assertThat(page.getWebResponse().getStatusCode(), equalTo(200)); } @Test public void contextPathExplicit() throws IOException { this.webClient.setWebConnection(new MockMvcWebConnection(this.mockMvc, this.webClient, "/context")); - Page page = this.webClient.getPage("http://localhost/context/a"); - assertThat(page.getWebResponse().getStatusCode(), equalTo(200)); } @Test public void contextPathEmpty() throws IOException { this.webClient.setWebConnection(new MockMvcWebConnection(this.mockMvc, this.webClient, "")); - Page page = this.webClient.getPage("http://localhost/context/a"); - assertThat(page.getWebResponse().getStatusCode(), equalTo(200)); } @Test public void forward() throws IOException { this.webClient.setWebConnection(new MockMvcWebConnection(this.mockMvc, this.webClient, "")); - Page page = this.webClient.getPage("http://localhost/forward"); - assertThat(page.getWebResponse().getContentAsString(), equalTo("hello")); } diff --git a/spring-tx/src/main/java/org/springframework/jca/cci/object/SimpleRecordOperation.java b/spring-tx/src/main/java/org/springframework/jca/cci/object/SimpleRecordOperation.java index efbec34e4a..6fa68d0559 100644 --- a/spring-tx/src/main/java/org/springframework/jca/cci/object/SimpleRecordOperation.java +++ b/spring-tx/src/main/java/org/springframework/jca/cci/object/SimpleRecordOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import javax.resource.cci.InteractionSpec; import javax.resource.cci.Record; import org.springframework.dao.DataAccessException; +import org.springframework.lang.Nullable; /** * EIS operation object that accepts a passed-in CCI input Record @@ -56,6 +57,7 @@ public class SimpleRecordOperation extends EisOperation { * @throws DataAccessException if there is any problem * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record) */ + @Nullable public Record execute(Record inputRecord) throws DataAccessException { return getCciTemplate().execute(getInteractionSpec(), inputRecord); } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java index f24fa8f05d..d1704eaae8 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -93,12 +93,7 @@ public class TransactionInterceptor extends TransactionAspectSupport implements Class targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... - return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { - @Override - public Object proceedWithInvocation() throws Throwable { - return invocation.proceed(); - } - }); + return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); } diff --git a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java index a2433bc5bb..250e59100b 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java @@ -1352,7 +1352,7 @@ public class HttpHeaders implements MultiValueMap, Serializable } @Override - public void addAll(String key, List values) { + public void addAll(String key, List values) { List currentValues = this.headers.computeIfAbsent(key, k -> new LinkedList<>()); currentValues.addAll(values); } diff --git a/spring-web/src/main/java/org/springframework/http/client/reactive/ClientHttpResponse.java b/spring-web/src/main/java/org/springframework/http/client/reactive/ClientHttpResponse.java index 148c03b71e..b0563927bd 100644 --- a/spring-web/src/main/java/org/springframework/http/client/reactive/ClientHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/client/reactive/ClientHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ import org.springframework.util.MultiValueMap; public interface ClientHttpResponse extends ReactiveHttpInputMessage { /** - * @return the HTTP status as an {@link HttpStatus} enum value + * Return the HTTP status as an {@link HttpStatus} enum value. */ HttpStatus getStatusCode(); diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java index a0066e788c..418c00909f 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java @@ -33,7 +33,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; -import com.fasterxml.jackson.databind.type.TypeFactory; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -142,17 +141,12 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpMes private DataBuffer encodeValue(Object value, @Nullable MimeType mimeType, DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable Map hints) { - TypeFactory typeFactory = this.objectMapper.getTypeFactory(); - JavaType javaType = typeFactory.constructType(elementType.getType()); - if (elementType.isInstance(value)) { - javaType = getJavaType(elementType.getType(), null); - } - + JavaType javaType = getJavaType(elementType.getType(), null); Class jsonView = (hints != null ? (Class) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null); ObjectWriter writer = (jsonView != null ? this.objectMapper.writerWithView(jsonView) : this.objectMapper.writer()); - if (javaType != null && javaType.isContainerType()) { + if (javaType.isContainerType()) { writer = writer.forType(javaType); } diff --git a/spring-web/src/main/java/org/springframework/web/context/request/RequestContextHolder.java b/spring-web/src/main/java/org/springframework/web/context/request/RequestContextHolder.java index 6a7a1e4fdd..be50f55780 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/RequestContextHolder.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/RequestContextHolder.java @@ -68,7 +68,7 @@ public abstract class RequestContextHolder { * @param attributes the RequestAttributes to expose * @see #setRequestAttributes(RequestAttributes, boolean) */ - public static void setRequestAttributes(RequestAttributes attributes) { + public static void setRequestAttributes(@Nullable RequestAttributes attributes) { setRequestAttributes(attributes, false); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/UrlBasedViewResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/UrlBasedViewResolver.java index 27e2237032..6486577bce 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/UrlBasedViewResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/UrlBasedViewResolver.java @@ -23,6 +23,7 @@ import reactor.core.publisher.Mono; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.PatternMatchUtils; @@ -259,7 +260,14 @@ public class UrlBasedViewResolver extends ViewResolverSupport implements ViewRes } private View applyLifecycleMethods(String viewName, AbstractView view) { - return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName); + ApplicationContext context = getApplicationContext(); + if (context != null) { + Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName); + if (initialized instanceof View) { + return (View) initialized; + } + } + return view; } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolverSupport.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolverSupport.java index f7658c9cde..3436848d7f 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolverSupport.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolverSupport.java @@ -96,6 +96,7 @@ public abstract class ViewResolverSupport implements ApplicationContextAware, Or this.applicationContext = applicationContext; } + @Nullable public ApplicationContext getApplicationContext() { return this.applicationContext; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java index 2391518422..2da809bd27 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/MappedInterceptor.java @@ -111,7 +111,7 @@ public final class MappedInterceptor implements HandlerInterceptor { } /** - * The configured PathMatcher, or {@code null}. + * The configured PathMatcher, or {@code null} if none. */ @Nullable public PathMatcher getPathMatcher() { @@ -121,6 +121,7 @@ public final class MappedInterceptor implements HandlerInterceptor { /** * The path into the application the interceptor is mapped to. */ + @Nullable public String[] getPathPatterns() { return this.includePatterns; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java index d20c7d48aa..e9fe6f8d2e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java @@ -278,7 +278,6 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe * Return the generic type of the {@code returnType} (or of the nested type * if it is an {@link HttpEntity}). */ - @Nullable private Type getGenericType(MethodParameter returnType) { if (HttpEntity.class.isAssignableFrom(returnType.getParameterType())) { return ResolvableType.forType(returnType.getGenericParameterType()).getGeneric().getType(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java index c891dad180..4566c11837 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java @@ -519,11 +519,12 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements private View applyLifecycleMethods(String viewName, AbstractView view) { ApplicationContext context = getApplicationContext(); if (context != null) { - return (View) context.getAutowireCapableBeanFactory().initializeBean(view, viewName); - } - else { - return view; + Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName); + if (initialized instanceof View) { + return (View) initialized; + } } + return view; } /**