diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java index 9104ea91ec..abdff8ebf1 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java @@ -104,11 +104,11 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence private final AspectInstanceFactory aspectInstanceFactory; /** - * The name of the aspect (ref bean) in which this advice was defined (used - * when determining advice precedence so that we can determine + * The name of the aspect (ref bean) in which this advice was defined + * (used when determining advice precedence so that we can determine * whether two pieces of advice come from the same aspect). */ - private String aspectName; + private String aspectName = ""; /** * The order of declaration of this advice within the aspect. @@ -119,13 +119,16 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence * This will be non-null if the creator of this advice object knows the argument names * and sets them explicitly */ - private String[] argumentNames = null; + @Nullable + private String[] argumentNames; /** Non-null if after throwing advice binds the thrown value */ - private String throwingName = null; + @Nullable + private String throwingName; /** Non-null if after returning advice binds the return value */ - private String returningName = null; + @Nullable + private String returningName; private Class discoveredReturningType = Object.class; @@ -143,10 +146,12 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence */ private int joinPointStaticPartArgumentIndex = -1; + @Nullable private Map argumentBindings; private boolean argumentsIntrospected = false; + @Nullable private Type discoveredReturningGenericType; // Note: Unlike return type, no such generic information is needed for the throwing type, // since Java doesn't allow exception types to be parameterized. @@ -464,6 +469,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence } private void bindExplicitArguments(int numArgumentsLeftToBind) { + Assert.state(this.argumentNames != null, "No argument names available"); this.argumentBindings = new HashMap<>(); int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount(); @@ -504,7 +510,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence } // configure the pointcut expression accordingly. - configurePointcutParameters(argumentIndexOffset); + configurePointcutParameters(this.argumentNames, argumentIndexOffset); } /** @@ -512,7 +518,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence * pointcut parameters - but returning and throwing vars are handled differently * and must be removed from the list if present. */ - private void configurePointcutParameters(int argumentIndexOffset) { + private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) { int numParametersToRemove = argumentIndexOffset; if (this.returningName != null) { numParametersToRemove++; @@ -520,20 +526,20 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence if (this.throwingName != null) { numParametersToRemove++; } - String[] pointcutParameterNames = new String[this.argumentNames.length - numParametersToRemove]; + String[] pointcutParameterNames = new String[argumentNames.length - numParametersToRemove]; Class[] pointcutParameterTypes = new Class[pointcutParameterNames.length]; Class[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes(); int index = 0; - for (int i = 0; i < this.argumentNames.length; i++) { + for (int i = 0; i < argumentNames.length; i++) { if (i < argumentIndexOffset) { continue; } - if (this.argumentNames[i].equals(this.returningName) || - this.argumentNames[i].equals(this.throwingName)) { + if (argumentNames[i].equals(this.returningName) || + argumentNames[i].equals(this.throwingName)) { continue; } - pointcutParameterNames[index] = this.argumentNames[i]; + pointcutParameterNames[index] = argumentNames[i]; pointcutParameterTypes[index] = methodParameterTypes[i]; index++; } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java index 70e9a72e65..1ec800eb02 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java @@ -114,6 +114,7 @@ import org.springframework.util.StringUtils; * returning {@code null} in the case that the parameter names cannot be discovered. * * @author Adrian Colyer + * @author Juergen Hoeller * @since 2.0 */ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscoverer { @@ -155,26 +156,23 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov } - private boolean raiseExceptions; - - /** - * If the advice is afterReturning, and binds the return value, this is the parameter name used. - */ - private String returningName; - - /** - * If the advice is afterThrowing, and binds the thrown value, this is the parameter name used. - */ - private String throwingName; - - /** - * The pointcut expression associated with the advice, as a simple String. - */ + /** The pointcut expression associated with the advice, as a simple String */ + @Nullable private String pointcutExpression; - private Class[] argumentTypes; + private boolean raiseExceptions; - private String[] parameterNameBindings; + /** If the advice is afterReturning, and binds the return value, this is the parameter name used */ + @Nullable + private String returningName; + + /** If the advice is afterThrowing, and binds the thrown value, this is the parameter name used */ + @Nullable + private String throwingName; + + private Class[] argumentTypes = new Class[0]; + + private String[] parameterNameBindings = new String[0]; private int numberOfRemainingUnboundArguments; @@ -202,7 +200,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov * returning variable name must be specified. * @param returningName the name of the returning variable */ - public void setReturningName(String returningName) { + public void setReturningName(@Nullable String returningName) { this.returningName = returningName; } @@ -211,7 +209,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov * throwing variable name must be specified. * @param throwingName the name of the throwing variable */ - public void setThrowingName(String throwingName) { + public void setThrowingName(@Nullable String throwingName) { this.throwingName = throwingName; } @@ -781,6 +779,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov private int numTokensConsumed; + @Nullable private String text; public PointcutBody(int tokens, @Nullable String text) { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java index 784ce99e55..91ab40742a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java @@ -102,16 +102,20 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class); + @Nullable private Class pointcutDeclarationScope; private String[] pointcutParameterNames = new String[0]; private Class[] pointcutParameterTypes = new Class[0]; + @Nullable private BeanFactory beanFactory; + @Nullable private transient ClassLoader pointcutClassLoader; + @Nullable private transient PointcutExpression pointcutExpression; private transient Map shadowMatchCache = new ConcurrentHashMap<>(32); @@ -169,13 +173,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut @Override public ClassFilter getClassFilter() { - checkReadyToMatch(); + obtainPointcutExpression(); return this; } @Override public MethodMatcher getMethodMatcher() { - checkReadyToMatch(); + obtainPointcutExpression(); return this; } @@ -184,7 +188,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut * Check whether this pointcut is ready to match, * lazily building the underlying AspectJ pointcut expression. */ - private void checkReadyToMatch() { + private PointcutExpression obtainPointcutExpression() { if (getExpression() == null) { throw new IllegalStateException("Must set property 'expression' before attempting to match"); } @@ -192,6 +196,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut this.pointcutClassLoader = determinePointcutClassLoader(); this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader); } + return this.pointcutExpression; } /** @@ -258,16 +263,15 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut * Return the underlying AspectJ pointcut expression. */ public PointcutExpression getPointcutExpression() { - checkReadyToMatch(); - return this.pointcutExpression; + return obtainPointcutExpression(); } @Override public boolean matches(Class targetClass) { - checkReadyToMatch(); + PointcutExpression pointcutExpression = obtainPointcutExpression(); try { try { - return this.pointcutExpression.couldMatchJoinPointsInType(targetClass); + return pointcutExpression.couldMatchJoinPointsInType(targetClass); } catch (ReflectionWorldException ex) { logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex); @@ -286,7 +290,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut @Override public boolean matches(Method method, @Nullable Class targetClass, boolean beanHasIntroductions) { - checkReadyToMatch(); + obtainPointcutExpression(); Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass); ShadowMatch shadowMatch = getShadowMatch(targetMethod, method); @@ -321,13 +325,12 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut @Override public boolean isRuntime() { - checkReadyToMatch(); - return this.pointcutExpression.mayNeedDynamicTest(); + return obtainPointcutExpression().mayNeedDynamicTest(); } @Override public boolean matches(Method method, @Nullable Class targetClass, Object... args) { - checkReadyToMatch(); + obtainPointcutExpression(); ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method); ShadowMatch originalShadowMatch = getShadowMatch(method, method); @@ -436,7 +439,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut if (shadowMatch == null) { try { try { - shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch); + shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch); } catch (ReflectionWorldException ex) { // Failed to introspect target method, probably because it has been loaded @@ -454,7 +457,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut if (shadowMatch == null && targetMethod != originalMethod) { methodToMatch = originalMethod; try { - shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch); + shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch); } catch (ReflectionWorldException ex3) { // Could neither introspect the target class nor the proxy class -> @@ -519,18 +522,16 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut public String toString() { StringBuilder sb = new StringBuilder(); sb.append("AspectJExpressionPointcut: "); - if (this.pointcutParameterNames != null && this.pointcutParameterTypes != null) { - sb.append("("); - for (int i = 0; i < this.pointcutParameterTypes.length; i++) { - sb.append(this.pointcutParameterTypes[i].getName()); - sb.append(" "); - sb.append(this.pointcutParameterNames[i]); - if ((i+1) < this.pointcutParameterTypes.length) { - sb.append(", "); - } + sb.append("("); + for (int i = 0; i < this.pointcutParameterTypes.length; i++) { + sb.append(this.pointcutParameterTypes[i].getName()); + sb.append(" "); + sb.append(this.pointcutParameterNames[i]); + if ((i+1) < this.pointcutParameterTypes.length) { + sb.append(", "); } - sb.append(")"); } + sb.append(")"); sb.append(" "); if (getExpression() != null) { sb.append(getExpression()); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java index 14ad6c67a9..5a534e0f6a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.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 org.aopalliance.aop.Advice; import org.springframework.aop.Pointcut; import org.springframework.aop.PointcutAdvisor; import org.springframework.core.Ordered; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -38,6 +39,7 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered { private final Pointcut pointcut; + @Nullable private Integer order; diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.java index 941047bbfe..346fe83c61 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPoint.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. @@ -57,12 +57,15 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, private final ProxyMethodInvocation methodInvocation; + @Nullable private Object[] defensiveCopyOfArgs; /** Lazily initialized signature object */ + @Nullable private Signature signature; /** Lazily initialized source location object */ + @Nullable private SourceLocation sourceLocation; @@ -178,6 +181,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, */ private class MethodSignatureImpl implements MethodSignature { + @Nullable private volatile String[] parameterNames; @Override @@ -216,6 +220,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, } @Override + @Nullable public String[] getParameterNames() { if (this.parameterNames == null) { this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod()); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/RuntimeTestWalker.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/RuntimeTestWalker.java index 44fb00a4ad..30a3213de1 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/RuntimeTestWalker.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/RuntimeTestWalker.java @@ -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. @@ -37,6 +37,7 @@ import org.aspectj.weaver.reflect.ReflectionVar; import org.aspectj.weaver.reflect.ShadowMatchImpl; import org.aspectj.weaver.tools.ShadowMatch; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -78,6 +79,7 @@ class RuntimeTestWalker { } + @Nullable private final Test runtimeTest; diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java index d075741490..8b5eec1abe 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java @@ -20,6 +20,7 @@ import org.aspectj.weaver.tools.PointcutParser; import org.aspectj.weaver.tools.TypePatternMatcher; import org.springframework.aop.ClassFilter; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -32,8 +33,9 @@ import org.springframework.util.StringUtils; */ public class TypePatternClassFilter implements ClassFilter { - private String typePattern; + private String typePattern = ""; + @Nullable private TypePatternMatcher aspectJTypePatternMatcher; @@ -51,8 +53,6 @@ public class TypePatternClassFilter implements ClassFilter { * Create a fully configured {@link TypePatternClassFilter} using the * given type pattern. * @param typePattern the type pattern that AspectJ weaver should parse - * @throws IllegalArgumentException if the supplied {@code typePattern} is {@code null} - * or is recognized as invalid */ public TypePatternClassFilter(String typePattern) { setTypePattern(typePattern); @@ -73,8 +73,6 @@ public class TypePatternClassFilter implements ClassFilter { * that implements it. *

These conventions are established by AspectJ, not Spring AOP. * @param typePattern the type pattern that AspectJ weaver should parse - * @throws IllegalArgumentException if the supplied {@code typePattern} is {@code null} - * or is recognized as invalid */ public void setTypePattern(String typePattern) { Assert.notNull(typePattern, "Type pattern must not be null"); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java index 1bef6b684f..6065e0bed2 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java @@ -212,9 +212,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac throw new IllegalStateException("Unknown annotation type: " + annotation.toString()); } - @Nullable private String resolveExpression(A annotation) throws Exception { - String expression = null; for (String methodName : EXPRESSION_PROPERTIES) { Method method; try { @@ -226,11 +224,11 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac if (method != null) { String candidate = (String) method.invoke(annotation); if (StringUtils.hasText(candidate)) { - expression = candidate; + return candidate; } } } - return expression; + throw new IllegalStateException("Failed to resolve expression: " + annotation); } public AspectJAnnotationType getAnnotationType() { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AnnotationAwareAspectJAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AnnotationAwareAspectJAutoProxyCreator.java index 25369cb1fc..fa9c0106d7 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AnnotationAwareAspectJAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AnnotationAwareAspectJAutoProxyCreator.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,6 +24,7 @@ import org.springframework.aop.Advisor; import org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -48,10 +49,13 @@ import org.springframework.util.Assert; @SuppressWarnings("serial") public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { + @Nullable private List includePatterns; + @Nullable private AspectJAdvisorFactory aspectJAdvisorFactory; + @Nullable private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder; @@ -87,7 +91,9 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA // Add all the Spring advisors found according to superclass rules. List advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. - advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); + if (this.aspectJAdvisorsBuilder != null) { + advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); + } return advisors; } @@ -101,7 +107,8 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA // proxied by that interface and fail at runtime as the advice method is not // defined on the interface. We could potentially relax the restriction about // not advising aspects in the future. - return (super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory.isAspect(beanClass)); + return (super.isInfrastructureClass(beanClass) || + (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass))); } /** diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java index 9539895a09..e7a2dcd578 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java @@ -104,19 +104,19 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst @Override public Object getAspectCreationMutex() { - if (this.beanFactory != null) { - if (this.beanFactory.isSingleton(name)) { - // Rely on singleton semantics provided by the factory -> no local lock. - return null; - } - else if (this.beanFactory instanceof ConfigurableBeanFactory) { - // No singleton guarantees from the factory -> let's lock locally but - // reuse the factory's singleton lock, just in case a lazy dependency - // of our advice bean happens to trigger the singleton lock implicitly... - return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex(); - } + if (this.beanFactory.isSingleton(this.name)) { + // Rely on singleton semantics provided by the factory -> no local lock. + return null; + } + else if (this.beanFactory instanceof ConfigurableBeanFactory) { + // No singleton guarantees from the factory -> let's lock locally but + // reuse the factory's singleton lock, just in case a lazy dependency + // of our advice bean happens to trigger the singleton lock implicitly... + return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex(); + } + else { + return this; } - return this; } /** diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java index e481eb9322..3a1a8575ee 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.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. @@ -27,6 +27,7 @@ import org.aspectj.lang.reflect.PerClauseKind; import org.springframework.aop.Advisor; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -43,6 +44,7 @@ public class BeanFactoryAspectJAdvisorsBuilder { private final AspectJAdvisorFactory advisorFactory; + @Nullable private volatile List aspectBeanNames; private final Map> advisorsCache = new ConcurrentHashMap<>(); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java index 6a83acbafa..85c49d46e8 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java @@ -70,10 +70,13 @@ class InstantiationModelAwarePointcutAdvisorImpl private final boolean lazy; + @Nullable private Advice instantiatedAdvice; + @Nullable private Boolean isBeforeAdvice; + @Nullable private Boolean isAfterAdvice; @@ -267,10 +270,12 @@ class InstantiationModelAwarePointcutAdvisorImpl private final Pointcut preInstantiationPointcut; + @Nullable private LazySingletonAspectInstanceFactoryDecorator aspectInstanceFactory; private PerTargetInstantiationModelPointcut(AspectJExpressionPointcut declaredPointcut, Pointcut preInstantiationPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory) { + this.declaredPointcut = declaredPointcut; this.preInstantiationPointcut = preInstantiationPointcut; if (aspectInstanceFactory instanceof LazySingletonAspectInstanceFactoryDecorator) { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java index 18bf9f327b..e6bc38f37a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.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.aop.aspectj.annotation; import java.io.Serializable; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -32,6 +33,7 @@ public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwar private final MetadataAwareAspectInstanceFactory maaif; + @Nullable private volatile Object materialized; @@ -47,20 +49,24 @@ public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwar @Override public Object getAspectInstance() { - if (this.materialized == null) { + Object aspectInstance = this.materialized; + if (aspectInstance == null) { Object mutex = this.maaif.getAspectCreationMutex(); if (mutex == null) { - this.materialized = this.maaif.getAspectInstance(); + aspectInstance = this.maaif.getAspectInstance(); + this.materialized = aspectInstance; } else { synchronized (mutex) { - if (this.materialized == null) { - this.materialized = this.maaif.getAspectInstance(); + aspectInstance = this.materialized; + if (aspectInstance == null) { + aspectInstance = this.maaif.getAspectInstance(); + this.materialized = aspectInstance; } } } } - return this.materialized; + return aspectInstance; } public boolean isMaterialized() { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java index f1897370bf..73d58a01b4 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java @@ -86,6 +86,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto } + @Nullable private final BeanFactory beanFactory; @@ -209,7 +210,9 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]); ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); - ajexp.setBeanFactory(this.beanFactory); + if (this.beanFactory != null) { + ajexp.setBeanFactory(this.beanFactory); + } return ajexp; } diff --git a/spring-aop/src/main/java/org/springframework/aop/config/MethodLocatingFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/config/MethodLocatingFactoryBean.java index 4acf03040e..78407f87dc 100644 --- a/spring-aop/src/main/java/org/springframework/aop/config/MethodLocatingFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/config/MethodLocatingFactoryBean.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. @@ -22,6 +22,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -32,10 +33,13 @@ import org.springframework.util.StringUtils; */ public class MethodLocatingFactoryBean implements FactoryBean, BeanFactoryAware { + @Nullable private String targetBeanName; + @Nullable private String methodName; + @Nullable private Method method; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java index aad094424d..7626443947 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -41,19 +42,25 @@ import org.springframework.util.ClassUtils; public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig implements FactoryBean, BeanClassLoaderAware, InitializingBean { + @Nullable private Object target; + @Nullable private Class[] proxyInterfaces; + @Nullable private Object[] preInterceptors; + @Nullable private Object[] postInterceptors; /** Default is global AdvisorAdapterRegistry */ private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance(); + @Nullable private transient ClassLoader proxyClassLoader; + @Nullable private Object proxy; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java index 05c39b01d8..e01ce0b229 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java @@ -220,8 +220,11 @@ public abstract class AopProxyUtils { * @return a cloned argument array, or the original if no adaptation is needed * @since 4.2.3 */ - static Object[] adaptArgumentsIfNecessary(Method method, Object... arguments) { - if (method.isVarArgs() && !ObjectUtils.isEmpty(arguments)) { + static Object[] adaptArgumentsIfNecessary(Method method, @Nullable Object[] arguments) { + if (ObjectUtils.isEmpty(arguments)) { + return new Object[0]; + } + if (method.isVarArgs()) { Class[] paramTypes = method.getParameterTypes(); if (paramTypes.length == arguments.length) { int varargIndex = paramTypes.length - 1; 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 e3524ecf7c..b82eb09b4d 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 @@ -20,6 +20,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.UndeclaredThrowableException; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -102,14 +103,16 @@ class CglibAopProxy implements AopProxy, Serializable { /** The configuration used to configure this proxy */ protected final AdvisedSupport advised; + @Nullable protected Object[] constructorArgs; + @Nullable protected Class[] constructorArgTypes; /** Dispatcher used for methods on Advised */ private final transient AdvisedDispatcher advisedDispatcher; - private transient Map fixedInterceptorMap; + private transient Map fixedInterceptorMap = Collections.emptyMap(); private transient int fixedInterceptorOffset; @@ -216,7 +219,7 @@ class CglibAopProxy implements AopProxy, Serializable { protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { enhancer.setInterceptDuringConstruction(false); enhancer.setCallbacks(callbacks); - return (this.constructorArgs != null ? + return (this.constructorArgs != null && this.constructorArgTypes != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create()); } @@ -409,6 +412,7 @@ class CglibAopProxy implements AopProxy, Serializable { */ private static class StaticUnadvisedInterceptor implements MethodInterceptor, Serializable { + @Nullable private final Object target; public StaticUnadvisedInterceptor(@Nullable Object target) { @@ -430,6 +434,7 @@ class CglibAopProxy implements AopProxy, Serializable { */ private static class StaticUnadvisedExposedInterceptor implements MethodInterceptor, Serializable { + @Nullable private final Object target; public StaticUnadvisedExposedInterceptor(@Nullable Object target) { @@ -520,6 +525,7 @@ class CglibAopProxy implements AopProxy, Serializable { */ private static class StaticDispatcher implements Dispatcher, Serializable { + @Nullable private Object target; public StaticDispatcher(@Nullable Object target) { @@ -527,6 +533,7 @@ class CglibAopProxy implements AopProxy, Serializable { } @Override + @Nullable public Object loadObject() { return this.target; } @@ -610,8 +617,10 @@ class CglibAopProxy implements AopProxy, Serializable { private final List adviceChain; + @Nullable private final Object target; + @Nullable private final Class targetClass; public FixedChainStaticTargetInterceptor( @@ -960,6 +969,7 @@ class CglibAopProxy implements AopProxy, Serializable { */ private static class ClassLoaderAwareUndeclaredThrowableStrategy extends UndeclaredThrowableStrategy { + @Nullable private final ClassLoader classLoader; public ClassLoaderAwareUndeclaredThrowableStrategy(@Nullable ClassLoader classLoader) { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java index b1fac4c464..d224a93a1a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java @@ -46,6 +46,7 @@ import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -101,8 +102,10 @@ public class ProxyFactoryBean extends ProxyCreatorSupport protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private String[] interceptorNames; + @Nullable private String targetName; private boolean autodetectInterfaces = true; @@ -113,16 +116,19 @@ public class ProxyFactoryBean extends ProxyCreatorSupport private boolean freezeProxy = false; + @Nullable private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader(); private transient boolean classLoaderConfigured = false; + @Nullable private transient BeanFactory beanFactory; /** Whether the advisor chain has already been initialized */ private boolean advisorChainInitialized = false; /** If this is a singleton, the cached singleton proxy instance */ + @Nullable private Object singletonInstance; @@ -404,6 +410,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport * @return {@code true} if it's an Advisor or Advice */ private boolean isNamedBeanAnAdvisorOrAdvice(String beanName) { + Assert.state(this.beanFactory != null, "No BeanFactory set"); Class namedBeanClass = this.beanFactory.getType(beanName); if (namedBeanClass != null) { return (Advisor.class.isAssignableFrom(namedBeanClass) || Advice.class.isAssignableFrom(namedBeanClass)); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java index fbe0b04ce4..76e8887015 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java @@ -43,6 +43,7 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC */ private int order = Ordered.LOWEST_PRECEDENCE; + @Nullable private ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader(); private boolean classLoaderConfigured = false; @@ -77,6 +78,7 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC /** * Return the configured proxy ClassLoader for this processor. */ + @Nullable protected ClassLoader getProxyClassLoader() { return this.proxyClassLoader; } 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 0ea3839d8e..bad0ad6819 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 @@ -63,17 +63,20 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea protected final Object proxy; + @Nullable protected final Object target; protected final Method method; - protected Object[] arguments; + protected Object[] arguments = new Object[0]; + @Nullable private final Class targetClass; /** * Lazily initialized map of user-specific attributes for this invocation. */ + @Nullable private Map userAttributes; /** @@ -103,7 +106,7 @@ 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, + Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class targetClass, List interceptorsAndDynamicMethodMatchers) { this.proxy = proxy; @@ -143,7 +146,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea @Override public final Object[] getArguments() { - return (this.arguments != null ? this.arguments : new Object[0]); + return this.arguments; } @Override @@ -205,8 +208,8 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea */ @Override public MethodInvocation invocableClone() { - Object[] cloneArguments = null; - if (this.arguments != null) { + Object[] cloneArguments = this.arguments; + if (this.arguments.length > 0) { // Build an independent copy of the arguments array. cloneArguments = new Object[this.arguments.length]; System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length); @@ -223,7 +226,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea * @see java.lang.Object#clone() */ @Override - public MethodInvocation invocableClone(@Nullable Object... arguments) { + public MethodInvocation invocableClone(Object... arguments) { // Force initialization of the user attributes Map, // for having a shared Map reference in the clone. if (this.userAttributes == null) { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java index 9baa00cd93..a6cd126adc 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java @@ -97,6 +97,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport * Convenience constant for subclasses: Return value for "do not proxy". * @see #getAdvicesAndAdvisorsForBean */ + @Nullable protected static final Object[] DO_NOT_PROXY = null; /** @@ -124,8 +125,10 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport private boolean applyCommonInterceptorsFirst = true; + @Nullable private TargetSourceCreator[] customTargetSourceCreators; + @Nullable private BeanFactory beanFactory; private final Set targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractBeanFactoryAwareAdvisingPostProcessor.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractBeanFactoryAwareAdvisingPostProcessor.java index eaae6c5f3d..c17cdc05eb 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractBeanFactoryAwareAdvisingPostProcessor.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractBeanFactoryAwareAdvisingPostProcessor.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. @@ -21,6 +21,7 @@ import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.lang.Nullable; /** * Extension of {@link AbstractAutoProxyCreator} which implements {@link BeanFactoryAware}, @@ -39,6 +40,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; public abstract class AbstractBeanFactoryAwareAdvisingPostProcessor extends AbstractAdvisingBeanPostProcessor implements BeanFactoryAware { + @Nullable private ConfigurableListableBeanFactory beanFactory; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanFactoryAdvisorRetrievalHelper.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanFactoryAdvisorRetrievalHelper.java index ebb92c84c5..d69c6b2ff5 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanFactoryAdvisorRetrievalHelper.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanFactoryAdvisorRetrievalHelper.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. @@ -27,6 +27,7 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCurrentlyInCreationException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -43,6 +44,7 @@ public class BeanFactoryAdvisorRetrievalHelper { private final ConfigurableListableBeanFactory beanFactory; + @Nullable private String[] cachedAdvisorBeanNames; @@ -95,7 +97,8 @@ public class BeanFactoryAdvisorRetrievalHelper { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; - if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) { + String bceBeanName = bce.getBeanName(); + if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { if (logger.isDebugEnabled()) { logger.debug("Skipping advisor '" + name + "' with dependency on currently created bean: " + ex.getMessage()); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java index 78f620ba56..5fef007433 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.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. @@ -46,6 +46,7 @@ import org.springframework.util.StringUtils; @SuppressWarnings("serial") public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator { + @Nullable private List beanNames; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java index dccf975db9..3c3feef482 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.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.aop.framework.autoproxy; import org.springframework.beans.factory.BeanNameAware; +import org.springframework.lang.Nullable; /** * {@code BeanPostProcessor} implementation that creates AOP proxies based on all @@ -43,6 +44,7 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea private boolean usePrefix = false; + @Nullable private String advisorBeanNamePrefix; @@ -76,6 +78,7 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea * Return the prefix for bean names that will cause them to be included * for auto-proxying by this object. */ + @Nullable public String getAdvisorBeanNamePrefix() { return this.advisorBeanNamePrefix; } @@ -96,7 +99,11 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea */ @Override protected boolean isEligibleAdvisorBean(String beanName) { - return (!isUsePrefix() || beanName.startsWith(getAdvisorBeanNamePrefix())); + if (!isUsePrefix()) { + return true; + } + String prefix = getAdvisorBeanNamePrefix(); + return (prefix != null && beanName.startsWith(prefix)); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractTraceInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractTraceInterceptor.java index 00ae0a2d81..f2f07515a8 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractTraceInterceptor.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AbstractTraceInterceptor.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. @@ -24,6 +24,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.support.AopUtils; +import org.springframework.lang.Nullable; /** * Base {@code MethodInterceptor} implementation for tracing. @@ -50,6 +51,7 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser * The default {@code Log} instance used to write trace messages. * This instance is mapped to the implementing {@code Class}. */ + @Nullable protected transient Log defaultLogger = LogFactory.getLog(getClass()); /** @@ -83,7 +85,6 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser * but rather into a specific named category. *

NOTE: Specify either this property or "useDynamicLogger", not both. * @see org.apache.commons.logging.LogFactory#getLog(String) - * @see org.apache.log4j.Logger#getLogger(String) * @see java.util.logging.Logger#getLogger(String) */ public void setLoggerName(String loggerName) { diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java index 6c199533be..7d49865efc 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java @@ -72,10 +72,12 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { private final Map executors = new ConcurrentHashMap<>(16); + @Nullable private volatile Executor defaultExecutor; private AsyncUncaughtExceptionHandler exceptionHandler; + @Nullable private BeanFactory beanFactory; diff --git a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.java index c93d3dfeb3..8889e117a7 100644 --- a/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyFactoryBean.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. @@ -28,6 +28,8 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** @@ -56,9 +58,11 @@ public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean beanType = beanFactory.getType(this.targetBeanName); if (beanType == null) { throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName + diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AbstractBeanFactoryPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/AbstractBeanFactoryPointcutAdvisor.java index bb8fa93b0e..51ddede6f6 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AbstractBeanFactoryPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AbstractBeanFactoryPointcutAdvisor.java @@ -43,10 +43,13 @@ import org.springframework.util.Assert; @SuppressWarnings("serial") public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware { + @Nullable private String adviceBeanName; + @Nullable private BeanFactory beanFactory; + @Nullable private transient volatile Advice advice; private transient volatile Object adviceMonitor = new Object(); @@ -119,10 +122,12 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu // reuse the factory's singleton lock, just in case a lazy dependency // of our advice bean happens to trigger the singleton lock implicitly... synchronized (this.adviceMonitor) { - if (this.advice == null) { - this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class); + advice = this.advice; + if (advice == null) { + advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class); + this.advice = advice; } - return this.advice; + return advice; } } } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.java index 44c7604351..93b3d3afe9 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AbstractExpressionPointcut.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. @@ -33,8 +33,10 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public abstract class AbstractExpressionPointcut implements ExpressionPointcut, Serializable { + @Nullable private String location; + @Nullable private String expression; diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.java index 06f9b9dc64..46bc775718 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.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. @@ -22,6 +22,7 @@ import org.aopalliance.aop.Advice; import org.springframework.aop.PointcutAdvisor; import org.springframework.core.Ordered; +import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -37,6 +38,7 @@ import org.springframework.util.ObjectUtils; @SuppressWarnings("serial") public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable { + @Nullable private Integer order; 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..f8974854a8 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 @@ -65,7 +65,7 @@ public abstract class AopUtils { * @see #isJdkDynamicProxy * @see #isCglibProxy */ - public static boolean isAopProxy(Object object) { + public static boolean isAopProxy(@Nullable Object object) { return (object instanceof SpringProxy && (Proxy.isProxyClass(object.getClass()) || ClassUtils.isCglibProxyClass(object.getClass()))); } @@ -78,7 +78,7 @@ public abstract class AopUtils { * @param object the object to check * @see java.lang.reflect.Proxy#isProxyClass */ - public static boolean isJdkDynamicProxy(Object object) { + public static boolean isJdkDynamicProxy(@Nullable Object object) { return (object instanceof SpringProxy && Proxy.isProxyClass(object.getClass())); } @@ -90,7 +90,7 @@ public abstract class AopUtils { * @param object the object to check * @see ClassUtils#isCglibProxy(Object) */ - public static boolean isCglibProxy(Object object) { + public static boolean isCglibProxy(@Nullable Object object) { return (object instanceof SpringProxy && ClassUtils.isCglibProxy(object)); } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java index fd78bfd604..50a67d2ae2 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java @@ -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. @@ -22,7 +22,6 @@ import org.springframework.aop.ClassFilter; import org.springframework.aop.MethodMatcher; import org.springframework.aop.Pointcut; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; /** * Convenient class for building up pointcuts. All methods return @@ -188,21 +187,14 @@ public class ComposablePointcut implements Pointcut, Serializable { if (!(other instanceof ComposablePointcut)) { return false; } - ComposablePointcut that = (ComposablePointcut) other; - return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) && - ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher); + ComposablePointcut otherPointcut = (ComposablePointcut) other; + return (this.classFilter.equals(otherPointcut.classFilter) && + this.methodMatcher.equals(otherPointcut.methodMatcher)); } @Override public int hashCode() { - int code = 17; - if (this.classFilter != null) { - code = 37 * code + this.classFilter.hashCode(); - } - if (this.methodMatcher != null) { - code = 37 * code + this.methodMatcher.hashCode(); - } - return code; + return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode(); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java index 4092f1f92c..1f2e65f113 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java @@ -40,6 +40,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher private Class clazz; + @Nullable private String methodName; private volatile int evaluations; diff --git a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java index 1d807d9c20..2b2b7d85ee 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java @@ -23,7 +23,6 @@ import java.util.LinkedList; import java.util.List; import org.springframework.lang.Nullable; -import org.springframework.util.ObjectUtils; import org.springframework.util.PatternMatchUtils; /** @@ -105,12 +104,12 @@ public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut impleme @Override public boolean equals(Object other) { return (this == other || (other instanceof NameMatchMethodPointcut && - ObjectUtils.nullSafeEquals(this.mappedNames, ((NameMatchMethodPointcut) other).mappedNames))); + this.mappedNames.equals(((NameMatchMethodPointcut) other).mappedNames))); } @Override public int hashCode() { - return (this.mappedNames != null ? this.mappedNames.hashCode() : 0); + return this.mappedNames.hashCode(); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/RegexpMethodPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/RegexpMethodPointcutAdvisor.java index a5bb6d46f7..896963d36b 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/RegexpMethodPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/RegexpMethodPointcutAdvisor.java @@ -21,6 +21,7 @@ import java.io.Serializable; import org.aopalliance.aop.Advice; import org.springframework.aop.Pointcut; +import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -44,8 +45,10 @@ import org.springframework.util.ObjectUtils; @SuppressWarnings("serial") public class RegexpMethodPointcutAdvisor extends AbstractGenericPointcutAdvisor { + @Nullable private String[] patterns; + @Nullable private AbstractRegexpMethodPointcut pointcut; private final Object pointcutMonitor = new SerializableMonitor(); @@ -121,7 +124,9 @@ public class RegexpMethodPointcutAdvisor extends AbstractGenericPointcutAdvisor synchronized (this.pointcutMonitor) { if (this.pointcut == null) { this.pointcut = createPointcut(); - this.pointcut.setPatterns(this.patterns); + if (this.patterns != null) { + this.pointcut.setPatterns(this.patterns); + } } return pointcut; } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java index 5b69ffda00..2eb8b15bd5 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java @@ -23,7 +23,6 @@ import org.springframework.aop.MethodMatcher; import org.springframework.aop.Pointcut; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; /** * Simple Pointcut that looks for a specific Java 5 annotation @@ -127,21 +126,14 @@ public class AnnotationMatchingPointcut implements Pointcut { if (!(other instanceof AnnotationMatchingPointcut)) { return false; } - AnnotationMatchingPointcut that = (AnnotationMatchingPointcut) other; - return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) && - ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher); + AnnotationMatchingPointcut otherPointcut = (AnnotationMatchingPointcut) other; + return (this.classFilter.equals(otherPointcut.classFilter) && + this.methodMatcher.equals(otherPointcut.methodMatcher)); } @Override public int hashCode() { - int code = 17; - if (this.classFilter != null) { - code = 37 * code + this.classFilter.hashCode(); - } - if (this.methodMatcher != null) { - code = 37 * code + this.methodMatcher.hashCode(); - } - return code; + return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode(); } @Override diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java index 8c7558b670..fd0c7501a4 100644 --- a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java @@ -78,15 +78,16 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA private int autoGrowCollectionLimit = Integer.MAX_VALUE; + @Nullable Object wrappedObject; private String nestedPath = ""; + @Nullable Object rootObject; - /** - * Map with cached nested Accessors: nested path -> Accessor instance. - */ + /** Map with cached nested Accessors: nested path -> Accessor instance */ + @Nullable private Map nestedPropertyAccessors; @@ -199,7 +200,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA } public final Object getWrappedInstance() { - Assert.state(this.wrappedObject != null, "No wrapped instance"); + Assert.state(this.wrappedObject != null, "No wrapped object"); return this.wrappedObject; } @@ -218,8 +219,8 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA * Return the root object at the top of the path of this accessor. * @see #getNestedPath */ - @Nullable public final Object getRootInstance() { + Assert.state(this.rootObject != null, "No root object"); return this.rootObject; } @@ -228,8 +229,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA * @see #getNestedPath */ public final Class getRootClass() { - Assert.state(this.wrappedObject != null, "No root object"); - return this.rootObject.getClass(); + return getRootInstance().getClass(); } @Override @@ -287,6 +287,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA throw new InvalidPropertyException( getRootClass(), this.nestedPath + tokens.actualName, "No property handler found"); } + Assert.state(tokens.keys != null, "No token keys"); String lastKey = tokens.keys[tokens.keys.length - 1]; if (propValue.getClass().isArray()) { @@ -379,9 +380,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA private Object getPropertyHoldingValue(PropertyTokenHolder tokens) { // Apply indexes and map keys: fetch value for all keys but the last one. - PropertyTokenHolder getterTokens = new PropertyTokenHolder(); + Assert.state(tokens.keys != null, "No token keys"); + PropertyTokenHolder getterTokens = new PropertyTokenHolder(tokens.actualName); getterTokens.canonicalName = tokens.canonicalName; - getterTokens.actualName = tokens.actualName; getterTokens.keys = new String[tokens.keys.length - 1]; System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1); @@ -461,7 +462,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA } catch (InvocationTargetException ex) { PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent( - this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); + getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); if (ex.getTargetException() instanceof ClassCastException) { throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException()); } @@ -476,7 +477,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA } catch (Exception ex) { PropertyChangeEvent pce = new PropertyChangeEvent( - this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); + getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); throw new MethodInvocationException(pce, ex); } } @@ -582,12 +583,12 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA } catch (ConverterNotFoundException | IllegalStateException ex) { PropertyChangeEvent pce = - new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue); + new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue); throw new ConversionNotSupportedException(pce, requiredType, ex); } catch (ConversionException | IllegalArgumentException ex) { PropertyChangeEvent pce = - new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue); + new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue); throw new TypeMismatchException(pce, requiredType, ex); } } @@ -621,7 +622,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA if (tokens.keys != null) { if (value == null) { if (isAutoGrowNestedPaths()) { - value = setDefaultValue(tokens.actualName); + value = setDefaultValue(new PropertyTokenHolder(tokens.actualName)); } else { throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, @@ -865,13 +866,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA return nestedPa; } - private Object setDefaultValue(String propertyName) { - PropertyTokenHolder tokens = new PropertyTokenHolder(); - tokens.actualName = propertyName; - tokens.canonicalName = propertyName; - return setDefaultValue(tokens); - } - private Object setDefaultValue(PropertyTokenHolder tokens) { PropertyValue pv = createDefaultPropertyValue(tokens); setPropertyValue(tokens, pv); @@ -932,7 +926,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA * @return representation of the parsed property tokens */ private PropertyTokenHolder getPropertyNameTokens(String propertyName) { - PropertyTokenHolder tokens = new PropertyTokenHolder(); String actualName = null; List keys = new ArrayList<>(2); int searchIndex = 0; @@ -955,8 +948,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA } } } - tokens.actualName = (actualName != null ? actualName : propertyName); - tokens.canonicalName = tokens.actualName; + PropertyTokenHolder tokens = new PropertyTokenHolder(actualName != null ? actualName : propertyName); if (!keys.isEmpty()) { tokens.canonicalName += PROPERTY_KEY_PREFIX + StringUtils.collectionToDelimitedString(keys, PROPERTY_KEY_SUFFIX + PROPERTY_KEY_PREFIX) + @@ -1036,10 +1028,16 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA protected static class PropertyTokenHolder { - public String canonicalName; + public PropertyTokenHolder(String name) { + this.actualName = name; + this.canonicalName = name; + } public String actualName; + public String canonicalName; + + @Nullable public String[] keys; } diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttribute.java b/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttribute.java index e91736e8f2..b8e284e150 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttribute.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttribute.java @@ -31,8 +31,10 @@ public class BeanMetadataAttribute implements BeanMetadataElement { private final String name; + @Nullable private final Object value; + @Nullable private Object source; @@ -58,6 +60,7 @@ public class BeanMetadataAttribute implements BeanMetadataElement { /** * Return the value of the attribute. */ + @Nullable public Object getValue() { return this.value; } @@ -71,6 +74,7 @@ public class BeanMetadataAttribute implements BeanMetadataElement { } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttributeAccessor.java b/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttributeAccessor.java index 924474bd08..644655902a 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttributeAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanMetadataAttributeAccessor.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. @@ -30,6 +30,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport implements BeanMetadataElement { + @Nullable private Object source; @@ -42,6 +43,7 @@ public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport impl } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java index 7a5f9c5234..a1d20808f6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -499,7 +499,9 @@ public abstract class BeanUtils { return new MethodParameter(((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodParameter()); } else { - return new MethodParameter(pd.getWriteMethod(), 0); + Method writeMethod = pd.getWriteMethod(); + Assert.state(writeMethod != null, "No write method available"); + return new MethodParameter(writeMethod, 0); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java index 6a48196ce4..aaff2e63c5 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java @@ -66,11 +66,13 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements * Cached introspections results for this object, to prevent encountering * the cost of JavaBeans introspection every time. */ + @Nullable private CachedIntrospectionResults cachedIntrospectionResults; /** * The security context used for invoking the property methods */ + @Nullable private AccessControlContext acc; @@ -178,7 +180,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements * Set the security context used during the invocation of the wrapped instance methods. * Can be null. */ - public void setSecurityContext(AccessControlContext acc) { + public void setSecurityContext(@Nullable AccessControlContext acc) { this.acc = acc; } @@ -186,6 +188,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements * Return the security context used during the invocation of the wrapped instance methods. * Can be null. */ + @Nullable public AccessControlContext getSecurityContext() { return this.acc; } diff --git a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java index c3ebd465e2..bd58a5d687 100644 --- a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java +++ b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java @@ -261,12 +261,16 @@ class ExtendedBeanInfo implements BeanInfo { static class SimplePropertyDescriptor extends PropertyDescriptor { + @Nullable private Method readMethod; + @Nullable private Method writeMethod; + @Nullable private Class propertyType; + @Nullable private Class propertyEditorClass; public SimplePropertyDescriptor(PropertyDescriptor original) throws IntrospectionException { @@ -282,6 +286,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Method getReadMethod() { return this.readMethod; } @@ -292,6 +297,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Method getWriteMethod() { return this.writeMethod; } @@ -315,6 +321,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Class getPropertyEditorClass() { return this.propertyEditorClass; } @@ -345,18 +352,25 @@ class ExtendedBeanInfo implements BeanInfo { static class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor { + @Nullable private Method readMethod; + @Nullable private Method writeMethod; + @Nullable private Class propertyType; + @Nullable private Method indexedReadMethod; + @Nullable private Method indexedWriteMethod; + @Nullable private Class indexedPropertyType; + @Nullable private Class propertyEditorClass; public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original) throws IntrospectionException { @@ -379,6 +393,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Method getReadMethod() { return this.readMethod; } @@ -389,6 +404,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Method getWriteMethod() { return this.writeMethod; } @@ -412,6 +428,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Method getIndexedReadMethod() { return this.indexedReadMethod; } @@ -422,6 +439,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Method getIndexedWriteMethod() { return this.indexedWriteMethod; } @@ -446,6 +464,7 @@ class ExtendedBeanInfo implements BeanInfo { } @Override + @Nullable public Class getPropertyEditorClass() { return this.propertyEditorClass; } diff --git a/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java index 21f3f79858..a1c1acb572 100644 --- a/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java +++ b/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java @@ -28,6 +28,7 @@ import org.springframework.core.BridgeMethodResolver; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -44,14 +45,19 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { private final Class beanClass; + @Nullable private final Method readMethod; + @Nullable private final Method writeMethod; + @Nullable private volatile Set ambiguousWriteMethods; + @Nullable private MethodParameter writeMethodParameter; + @Nullable private Class propertyType; private final Class propertyEditorClass; @@ -116,16 +122,19 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { } @Override + @Nullable public Method getReadMethod() { return this.readMethod; } @Override + @Nullable public Method getWriteMethod() { return this.writeMethod; } public Method getWriteMethodForActualAccess() { + Assert.state(this.writeMethod != null, "No write method available"); Set ambiguousCandidates = this.ambiguousWriteMethods; if (ambiguousCandidates != null) { this.ambiguousWriteMethods = null; @@ -137,10 +146,12 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { } public MethodParameter getWriteMethodParameter() { + Assert.state(this.writeMethodParameter != null, "No write method available"); return this.writeMethodParameter; } @Override + @Nullable public Class getPropertyType() { return this.propertyType; } diff --git a/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java b/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java index 8e6b5839c7..af3ff3ad92 100644 --- a/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java +++ b/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java @@ -41,6 +41,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable { private final List propertyValueList; + @Nullable private Set processedProperties; private volatile boolean converted = false; diff --git a/spring-beans/src/main/java/org/springframework/beans/NotWritablePropertyException.java b/spring-beans/src/main/java/org/springframework/beans/NotWritablePropertyException.java index cac0a15d90..1399c69e6c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/NotWritablePropertyException.java +++ b/spring-beans/src/main/java/org/springframework/beans/NotWritablePropertyException.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. @@ -29,7 +29,8 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class NotWritablePropertyException extends InvalidPropertyException { - private String[] possibleMatches = null; + @Nullable + private String[] possibleMatches; /** diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java b/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java index 32b429590a..bceb1c2e61 100644 --- a/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java +++ b/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java @@ -30,6 +30,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public abstract class PropertyAccessException extends BeansException { + @Nullable private transient PropertyChangeEvent propertyChangeEvent; diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java index 1fe6fbe932..32361e94d3 100644 --- a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java @@ -91,20 +91,26 @@ import org.springframework.util.ClassUtils; */ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { + @Nullable private ConversionService conversionService; private boolean defaultEditorsActive = false; private boolean configValueEditorsActive = false; + @Nullable private Map, PropertyEditor> defaultEditors; + @Nullable private Map, PropertyEditor> overriddenDefaultEditors; + @Nullable private Map, PropertyEditor> customEditors; + @Nullable private Map customEditorsForPath; + @Nullable private Map, PropertyEditor> customEditorCache; @@ -378,7 +384,8 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { */ @Nullable private PropertyEditor getCustomEditor(String propertyName, @Nullable Class requiredType) { - CustomEditorHolder holder = this.customEditorsForPath.get(propertyName); + CustomEditorHolder holder = + (this.customEditorsForPath != null ? this.customEditorsForPath.get(propertyName) : null); return (holder != null ? holder.getPropertyEditor(requiredType) : null); } @@ -517,6 +524,7 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { private final PropertyEditor propertyEditor; + @Nullable private final Class registeredType; private CustomEditorHolder(PropertyEditor propertyEditor, @Nullable Class registeredType) { diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyValue.java b/spring-beans/src/main/java/org/springframework/beans/PropertyValue.java index e14689bc84..519840e019 100644 --- a/spring-beans/src/main/java/org/springframework/beans/PropertyValue.java +++ b/spring-beans/src/main/java/org/springframework/beans/PropertyValue.java @@ -44,18 +44,22 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri private final String name; + @Nullable private final Object value; private boolean optional = false; private boolean converted = false; + @Nullable private Object convertedValue; /** Package-visible field that indicates whether conversion is necessary */ + @Nullable volatile Boolean conversionNecessary; /** Package-visible field for caching the resolved property path tokens */ + @Nullable transient volatile Object resolvedTokens; @@ -177,6 +181,7 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri * Return the converted value of the constructor argument, * after processed type conversion. */ + @Nullable public synchronized Object getConvertedValue() { return this.convertedValue; } diff --git a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java index 6b52d6a931..d334440e44 100644 --- a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java +++ b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.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. @@ -59,6 +59,7 @@ class TypeConverterDelegate { private final PropertyEditorRegistrySupport propertyEditorRegistry; + @Nullable private final Object targetObject; @@ -314,7 +315,7 @@ class TypeConverterDelegate { private Object attemptToConvertStringToEnum(Class requiredType, String trimmedValue, Object currentConvertedValue) { Object convertedValue = currentConvertedValue; - if (Enum.class == requiredType) { + if (Enum.class == requiredType && this.targetObject != null) { // target type is declared as raw enum, treat the trimmed value as .FIELD_NAME int index = trimmedValue.lastIndexOf("."); if (index > - 1) { diff --git a/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java b/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java index 83c3614985..94ff02260b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.java +++ b/spring-beans/src/main/java/org/springframework/beans/TypeMismatchException.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. @@ -36,8 +36,10 @@ public class TypeMismatchException extends PropertyAccessException { public static final String ERROR_CODE = "typeMismatch"; + @Nullable private transient Object value; + @Nullable private Class requiredType; @@ -99,6 +101,7 @@ public class TypeMismatchException extends PropertyAccessException { * Return the offending value (may be {@code null}). */ @Override + @Nullable public Object getValue() { return this.value; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java index 157303b219..21884a1f29 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java @@ -34,10 +34,13 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class BeanCreationException extends FatalBeanException { + @Nullable private String beanName; + @Nullable private String resourceDescription; + @Nullable private List relatedCauses; @@ -119,6 +122,7 @@ public class BeanCreationException extends FatalBeanException { /** * Return the name of the bean requested, if any. */ + @Nullable public String getBeanName() { return this.beanName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanDefinitionStoreException.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanDefinitionStoreException.java index a568c9688d..44c23a3de8 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanDefinitionStoreException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanDefinitionStoreException.java @@ -30,8 +30,10 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class BeanDefinitionStoreException extends FatalBeanException { + @Nullable private String resourceDescription; + @Nullable private String beanName; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/CannotLoadBeanClassException.java b/spring-beans/src/main/java/org/springframework/beans/factory/CannotLoadBeanClassException.java index 9bd6127f3d..a963d2c1a3 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/CannotLoadBeanClassException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/CannotLoadBeanClassException.java @@ -29,10 +29,13 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class CannotLoadBeanClassException extends FatalBeanException { + @Nullable private String resourceDescription; + @Nullable private String beanName; + @Nullable private String beanClassName; @@ -78,6 +81,7 @@ public class CannotLoadBeanClassException extends FatalBeanException { * Return the description of the resource that the bean * definition came from. */ + @Nullable public String getResourceDescription() { return this.resourceDescription; } @@ -85,6 +89,7 @@ public class CannotLoadBeanClassException extends FatalBeanException { /** * Return the name of the bean requested. */ + @Nullable public String getBeanName() { return this.beanName; } @@ -92,6 +97,7 @@ public class CannotLoadBeanClassException extends FatalBeanException { /** * Return the name of the class we were trying to load. */ + @Nullable public String getBeanClassName() { return this.beanClassName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java b/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java index f129577052..4a6eda2bbf 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java @@ -24,6 +24,7 @@ import java.lang.reflect.Member; import org.springframework.core.MethodParameter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** * A simple descriptor for an injection point, pointing to a method/constructor @@ -36,10 +37,13 @@ import org.springframework.util.Assert; */ public class InjectionPoint { + @Nullable protected MethodParameter methodParameter; + @Nullable protected Field field; + @Nullable private volatile Annotation[] fieldAnnotations; @@ -99,18 +103,31 @@ public class InjectionPoint { return this.field; } + /** + * Return the wrapped MethodParameter, assuming it is present. + * @return the MethodParameter (never {@code null}) + * @throws IllegalStateException if no MethodParameter is available + * @since 5.0 + */ + protected final MethodParameter obtainMethodParameter() { + Assert.state(this.methodParameter != null, "Neither Field nor MethodParameter"); + return this.methodParameter; + } + /** * Obtain the annotations associated with the wrapped field or method/constructor parameter. */ public Annotation[] getAnnotations() { if (this.field != null) { - if (this.fieldAnnotations == null) { - this.fieldAnnotations = this.field.getAnnotations(); + Annotation[] fieldAnnotations = this.fieldAnnotations; + if (fieldAnnotations == null) { + fieldAnnotations = this.field.getAnnotations(); + this.fieldAnnotations = fieldAnnotations; } - return this.fieldAnnotations; + return fieldAnnotations; } else { - return this.methodParameter.getParameterAnnotations(); + return obtainMethodParameter().getParameterAnnotations(); } } @@ -123,7 +140,7 @@ public class InjectionPoint { @Nullable public A getAnnotation(Class annotationType) { return (this.field != null ? this.field.getAnnotation(annotationType) : - this.methodParameter.getParameterAnnotation(annotationType)); + obtainMethodParameter().getParameterAnnotation(annotationType)); } /** @@ -131,7 +148,7 @@ public class InjectionPoint { * indicating the injection type. */ public Class getDeclaredType() { - return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType()); + return (this.field != null ? this.field.getType() : obtainMethodParameter().getParameterType()); } /** @@ -139,7 +156,7 @@ public class InjectionPoint { * @return the Field / Method / Constructor as Member */ public Member getMember() { - return (this.field != null ? this.field : this.methodParameter.getMember()); + return (this.field != null ? this.field : obtainMethodParameter().getMember()); } /** @@ -152,7 +169,7 @@ public class InjectionPoint { * @return the Field / Method / Constructor as AnnotatedElement */ public AnnotatedElement getAnnotatedElement() { - return (this.field != null ? this.field : this.methodParameter.getAnnotatedElement()); + return (this.field != null ? this.field : obtainMethodParameter().getAnnotatedElement()); } @@ -165,18 +182,18 @@ public class InjectionPoint { return false; } InjectionPoint otherPoint = (InjectionPoint) other; - return (this.field != null ? this.field.equals(otherPoint.field) : - this.methodParameter.equals(otherPoint.methodParameter)); + return (ObjectUtils.nullSafeEquals(this.field, otherPoint.field) && + ObjectUtils.nullSafeEquals(this.methodParameter, otherPoint.methodParameter)); } @Override public int hashCode() { - return (this.field != null ? this.field.hashCode() : this.methodParameter.hashCode()); + return (this.field != null ? this.field.hashCode() : ObjectUtils.nullSafeHashCode(this.methodParameter)); } @Override public String toString() { - return (this.field != null ? "field '" + this.field.getName() + "'" : this.methodParameter.toString()); + return (this.field != null ? "field '" + this.field.getName() + "'" : String.valueOf(this.methodParameter)); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java b/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java index 4197ce1482..539b253424 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.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. @@ -35,8 +35,10 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class NoSuchBeanDefinitionException extends BeansException { + @Nullable private String beanName; + @Nullable private ResolvableType resolvableType; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java b/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java index 83b6c1ddc1..a5de119729 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.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. @@ -32,6 +32,7 @@ import org.springframework.util.StringUtils; @SuppressWarnings("serial") public class UnsatisfiedDependencyException extends BeanCreationException { + @Nullable private InjectionPoint injectionPoint; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 77c18c1079..10055b9c50 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -128,6 +128,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean private int order = Ordered.LOWEST_PRECEDENCE - 2; + @Nullable private ConfigurableListableBeanFactory beanFactory; private final Set lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); @@ -242,6 +243,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean ReflectionUtils.doWithMethods(beanClass, method -> { Lookup lookup = method.getAnnotation(Lookup.class); if (lookup != null) { + Assert.state(beanFactory != null, "No BeanFactory available"); LookupOverride override = new LookupOverride(method, lookup.value()); try { RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName); @@ -504,7 +506,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean private void registerDependentBeans(@Nullable String beanName, Set autowiredBeanNames) { if (beanName != null) { for (String autowiredBeanName : autowiredBeanNames) { - if (this.beanFactory.containsBean(autowiredBeanName)) { + if (this.beanFactory != null && this.beanFactory.containsBean(autowiredBeanName)) { this.beanFactory.registerDependentBean(autowiredBeanName, beanName); } if (logger.isDebugEnabled()) { @@ -519,9 +521,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean * Resolve the specified cached method argument or field value. */ @Nullable - private Object resolvedCachedArgument(@Nullable String beanName, Object cachedArgument) { + private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) { if (cachedArgument instanceof DependencyDescriptor) { DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument; + Assert.state(beanFactory != null, "No BeanFactory available"); return this.beanFactory.resolveDependency(descriptor, beanName, null, null); } else { @@ -539,6 +542,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean private volatile boolean cached = false; + @Nullable private volatile Object cachedFieldValue; public AutowiredFieldElement(Field field, boolean required) { @@ -557,6 +561,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set autowiredBeanNames = new LinkedHashSet<>(1); + Assert.state(beanFactory != null, "No BeanFactory available"); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); @@ -603,6 +608,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean private volatile boolean cached = false; + @Nullable private volatile Object[] cachedMethodArguments; public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) { @@ -626,6 +632,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean arguments = new Object[paramTypes.length]; DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length]; Set autowiredBeans = new LinkedHashSet<>(paramTypes.length); + Assert.state(beanFactory != null, "No BeanFactory available"); TypeConverter typeConverter = beanFactory.getTypeConverter(); for (int i = 0; i < arguments.length; i++) { MethodParameter methodParam = new MethodParameter(method, i); @@ -647,9 +654,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean synchronized (this) { if (!this.cached) { if (arguments != null) { - this.cachedMethodArguments = new Object[paramTypes.length]; + Object[] cachedMethodArguments = new Object[paramTypes.length]; for (int i = 0; i < arguments.length; i++) { - this.cachedMethodArguments[i] = descriptors[i]; + cachedMethodArguments[i] = descriptors[i]; } registerDependentBeans(beanName, autowiredBeans); if (autowiredBeans.size() == paramTypes.length) { @@ -658,12 +665,13 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean String autowiredBeanName = it.next(); if (beanFactory.containsBean(autowiredBeanName)) { if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) { - this.cachedMethodArguments[i] = new ShortcutDependencyDescriptor( + cachedMethodArguments[i] = new ShortcutDependencyDescriptor( descriptors[i], autowiredBeanName, paramTypes[i]); } } } } + this.cachedMethodArguments = cachedMethodArguments; } else { this.cachedMethodArguments = null; @@ -685,12 +693,13 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean @Nullable private Object[] resolveCachedArguments(@Nullable String beanName) { - if (this.cachedMethodArguments == null) { + Object[] cachedMethodArguments = this.cachedMethodArguments; + if (cachedMethodArguments == null) { return null; } - Object[] arguments = new Object[this.cachedMethodArguments.length]; + Object[] arguments = new Object[cachedMethodArguments.length]; for (int i = 0; i < arguments.length; i++) { - arguments[i] = resolvedCachedArgument(beanName, this.cachedMethodArguments[i]); + arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]); } return arguments; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurer.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurer.java index 3e1ffe6a53..b3fc66d559 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurer.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/CustomAutowireConfigurer.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. @@ -51,8 +51,10 @@ public class CustomAutowireConfigurer implements BeanFactoryPostProcessor, BeanC private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered + @Nullable private Set customQualifierTypes; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java index d937cdfcdc..819b5babad 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java @@ -40,6 +40,7 @@ import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcess import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -77,14 +78,16 @@ public class InitDestroyAnnotationBeanPostProcessor protected transient Log logger = LogFactory.getLog(getClass()); + @Nullable private Class initAnnotationType; + @Nullable private Class destroyAnnotationType; private int order = Ordered.LOWEST_PRECEDENCE; - private transient final Map, LifecycleMetadata> lifecycleMetadataCache = - new ConcurrentHashMap<>(256); + @Nullable + private transient final Map, LifecycleMetadata> lifecycleMetadataCache = new ConcurrentHashMap<>(256); /** @@ -255,8 +258,10 @@ public class InitDestroyAnnotationBeanPostProcessor private final Collection destroyMethods; + @Nullable private volatile Set checkedInitMethods; + @Nullable private volatile Set checkedDestroyMethods; public LifecycleMetadata(Class targetClass, Collection initMethods, @@ -295,8 +300,9 @@ public class InitDestroyAnnotationBeanPostProcessor } public void invokeInitMethods(Object target, String beanName) throws Throwable { + Collection checkedInitMethods = this.checkedInitMethods; Collection initMethodsToIterate = - (this.checkedInitMethods != null ? this.checkedInitMethods : this.initMethods); + (checkedInitMethods != null ? checkedInitMethods : this.initMethods); if (!initMethodsToIterate.isEmpty()) { boolean debug = logger.isDebugEnabled(); for (LifecycleElement element : initMethodsToIterate) { @@ -309,8 +315,9 @@ public class InitDestroyAnnotationBeanPostProcessor } public void invokeDestroyMethods(Object target, String beanName) throws Throwable { + Collection checkedDestroyMethods = this.checkedDestroyMethods; Collection destroyMethodsToUse = - (this.checkedDestroyMethods != null ? this.checkedDestroyMethods : this.destroyMethods); + (checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods); if (!destroyMethodsToUse.isEmpty()) { boolean debug = logger.isDebugEnabled(); for (LifecycleElement element : destroyMethodsToUse) { @@ -323,8 +330,9 @@ public class InitDestroyAnnotationBeanPostProcessor } public boolean hasDestroyMethods() { + Collection checkedDestroyMethods = this.checkedDestroyMethods; Collection destroyMethodsToUse = - (this.checkedDestroyMethods != null ? this.checkedDestroyMethods : this.destroyMethods); + (checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods); return !destroyMethodsToUse.isEmpty(); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java index 1316b0ff46..a0f609260e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java @@ -53,6 +53,7 @@ public class InjectionMetadata { private final Collection injectedElements; + @Nullable private volatile Set checkedElements; @@ -78,8 +79,9 @@ public class InjectionMetadata { } public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { + Collection checkedElements = this.checkedElements; Collection elementsToIterate = - (this.checkedElements != null ? this.checkedElements : this.injectedElements); + (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { boolean debug = logger.isDebugEnabled(); for (InjectedElement element : elementsToIterate) { @@ -95,8 +97,9 @@ public class InjectionMetadata { * @since 3.2.13 */ public void clear(@Nullable PropertyValues pvs) { + Collection checkedElements = this.checkedElements; Collection elementsToIterate = - (this.checkedElements != null ? this.checkedElements : this.injectedElements); + (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { element.clearPropertySkipping(pvs); @@ -116,8 +119,10 @@ public class InjectionMetadata { protected final boolean isField; + @Nullable protected final PropertyDescriptor pd; + @Nullable protected volatile Boolean skip; protected InjectedElement(Member member, @Nullable PropertyDescriptor pd) { @@ -192,16 +197,18 @@ public class InjectionMetadata { * affected property as processed for other processors to ignore it. */ protected boolean checkPropertySkipping(@Nullable PropertyValues pvs) { - if (this.skip != null) { - return this.skip; + Boolean skip = this.skip; + if (skip != null) { + return skip; } if (pvs == null) { this.skip = false; return false; } synchronized (pvs) { - if (this.skip != null) { - return this.skip; + skip = this.skip; + if (skip != null) { + return skip; } if (this.pd != null) { if (pvs.contains(this.pd.getName())) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java index 625bb2cd5f..9aaf50837f 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.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. @@ -34,6 +34,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.beans.factory.InitializingBean; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -66,14 +67,18 @@ public abstract class AbstractFactoryBean private boolean singleton = true; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private BeanFactory beanFactory; private boolean initialized = false; + @Nullable private T singletonInstance; + @Nullable private T earlySingletonInstance; @@ -103,6 +108,7 @@ public abstract class AbstractFactoryBean /** * Return the BeanFactory that this bean runs in. */ + @Nullable protected BeanFactory getBeanFactory() { return this.beanFactory; } @@ -176,10 +182,9 @@ public abstract class AbstractFactoryBean * @return the singleton instance that this FactoryBean holds * @throws IllegalStateException if the singleton instance is not initialized */ + @Nullable private T getSingletonInstance() throws IllegalStateException { - if (!this.initialized) { - throw new IllegalStateException("Singleton instance not initialized yet"); - } + Assert.state(this.initialized, "Singleton instance not initialized yet"); return this.singletonInstance; } @@ -241,7 +246,7 @@ public abstract class AbstractFactoryBean * @throws Exception in case of shutdown errors * @see #createInstance() */ - protected void destroyInstance(T instance) throws Exception { + protected void destroyInstance(@Nullable T instance) throws Exception { } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionHolder.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionHolder.java index 6e831ef546..26e02b62af 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionHolder.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionHolder.java @@ -43,6 +43,7 @@ public class BeanDefinitionHolder implements BeanMetadataElement { private final String beanName; + @Nullable private final String[] aliases; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionVisitor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionVisitor.java index 6b0f1555be..39d571e482 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionVisitor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionVisitor.java @@ -47,6 +47,7 @@ import org.springframework.util.StringValueResolver; */ public class BeanDefinitionVisitor { + @Nullable private StringValueResolver valueResolver; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java index 86df44a2be..3e0b4000bb 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 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. @@ -29,6 +29,7 @@ public class BeanExpressionContext { private final ConfigurableBeanFactory beanFactory; + @Nullable private final Scope scope; @@ -42,6 +43,7 @@ public class BeanExpressionContext { return this.beanFactory; } + @Nullable public final Scope getScope() { return this.scope; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java index 0f375fb560..7ffc4f5000 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java @@ -91,6 +91,7 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single /** * Return this factory's class loader for loading bean classes. */ + @Nullable ClassLoader getBeanClassLoader(); /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java index 33d354b6e2..a9ebfcd31b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java @@ -435,16 +435,21 @@ public class ConstructorArgumentValues { */ public static class ValueHolder implements BeanMetadataElement { + @Nullable private Object value; + @Nullable private String type; + @Nullable private String name; + @Nullable private Object source; private boolean converted = false; + @Nullable private Object convertedValue; /** @@ -558,6 +563,7 @@ public class ConstructorArgumentValues { * Return the converted value of the constructor argument, * after processed type conversion. */ + @Nullable public synchronized Object getConvertedValue() { return this.convertedValue; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomEditorConfigurer.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomEditorConfigurer.java index 56d5b6feb2..42b2efd696 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomEditorConfigurer.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomEditorConfigurer.java @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyEditorRegistrar; import org.springframework.core.Ordered; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -98,8 +99,10 @@ public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered + @Nullable private PropertyEditorRegistrar[] propertyEditorRegistrars; + @Nullable private Map, Class> customEditors; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomScopeConfigurer.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomScopeConfigurer.java index d5844fd82b..59e9111e63 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomScopeConfigurer.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/CustomScopeConfigurer.java @@ -46,10 +46,12 @@ import org.springframework.util.ClassUtils; */ public class CustomScopeConfigurer implements BeanFactoryPostProcessor, BeanClassLoaderAware, Ordered { + @Nullable private Map scopes; private int order = Ordered.LOWEST_PRECEDENCE; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java index 8c187ab2ff..24e8802346 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java @@ -58,12 +58,15 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable private final Class declaringClass; + @Nullable private String methodName; + @Nullable private Class[] parameterTypes; private int parameterIndex; + @Nullable private String fieldName; private final boolean required; @@ -72,8 +75,10 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable private int nestingLevel = 1; + @Nullable private Class containingClass; + @Nullable private volatile ResolvableType resolvableType; @@ -98,8 +103,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable super(methodParameter); this.declaringClass = methodParameter.getDeclaringClass(); - if (this.methodParameter.getMethod() != null) { - this.methodName = this.methodParameter.getMethod().getName(); + if (methodParameter.getMethod() != null) { + this.methodName = methodParameter.getMethod().getName(); } this.parameterTypes = methodParameter.getExecutable().getParameterTypes(); this.parameterIndex = methodParameter.getParameterIndex(); @@ -170,7 +175,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable (kotlinPresent && KotlinDelegate.isNullable(this.field))); } else { - return !this.methodParameter.isOptional(); + return !obtainMethodParameter().isOptional(); } } @@ -282,12 +287,14 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable * @since 4.0 */ public ResolvableType getResolvableType() { - if (this.resolvableType == null) { - this.resolvableType = (this.field != null ? + ResolvableType resolvableType = this.resolvableType; + if (resolvableType == null) { + resolvableType = (this.field != null ? ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) : - ResolvableType.forMethodParameter(this.methodParameter)); + ResolvableType.forMethodParameter(obtainMethodParameter())); + this.resolvableType = resolvableType; } - return this.resolvableType; + return resolvableType; } /** @@ -333,7 +340,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable */ @Nullable public String getDependencyName() { - return (this.field != null ? this.field.getName() : this.methodParameter.getParameterName()); + return (this.field != null ? this.field.getName() : obtainMethodParameter().getParameterName()); } /** @@ -367,7 +374,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable } } else { - return this.methodParameter.getNestedParameterType(); + return obtainMethodParameter().getNestedParameterType(); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java index 921a0ed555..99925990a9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java @@ -16,6 +16,7 @@ package org.springframework.beans.factory.config; +import org.springframework.lang.Nullable; import org.springframework.util.StringValueResolver; /** @@ -37,6 +38,7 @@ public class EmbeddedValueResolver implements StringValueResolver { private final BeanExpressionContext exprContext; + @Nullable private final BeanExpressionResolver exprResolver; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBean.java index f41dc97d77..e6e65b23c2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBean.java @@ -24,6 +24,8 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; @@ -55,19 +57,26 @@ import org.springframework.util.StringUtils; public class FieldRetrievingFactoryBean implements FactoryBean, BeanNameAware, BeanClassLoaderAware, InitializingBean { + @Nullable private Class targetClass; + @Nullable private Object targetObject; + @Nullable private String targetField; + @Nullable private String staticField; + @Nullable private String beanName; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); // the field we will retrieve + @Nullable private Field fieldObject; @@ -85,6 +94,7 @@ public class FieldRetrievingFactoryBean /** * Return the target class on which the field is defined. */ + @Nullable public Class getTargetClass() { return targetClass; } @@ -103,6 +113,7 @@ public class FieldRetrievingFactoryBean /** * Return the target object on which the field is defined. */ + @Nullable public Object getTargetObject() { return this.targetObject; } @@ -121,6 +132,7 @@ public class FieldRetrievingFactoryBean /** * Return the name of the field to be retrieved. */ + @Nullable public String getTargetField() { return this.targetField; } @@ -168,6 +180,7 @@ public class FieldRetrievingFactoryBean // If no other property specified, consider bean name as static field expression. if (this.staticField == null) { this.staticField = this.beanName; + Assert.state(this.staticField != null, "No target field specified"); } // Try to parse static field into class and field. diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ListFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ListFactoryBean.java index 4a4cfe7816..8323eb3a95 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ListFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ListFactoryBean.java @@ -35,9 +35,11 @@ import org.springframework.lang.Nullable; */ public class ListFactoryBean extends AbstractFactoryBean> { + @Nullable private List sourceList; @SuppressWarnings("rawtypes") + @Nullable private Class targetListClass; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/MapFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/MapFactoryBean.java index 76b6a015e5..507e518e02 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/MapFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/MapFactoryBean.java @@ -35,9 +35,11 @@ import org.springframework.lang.Nullable; */ public class MapFactoryBean extends AbstractFactoryBean> { + @Nullable private Map sourceMap; @SuppressWarnings("rawtypes") + @Nullable private Class targetMapClass; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingBean.java index f9d087274c..5faa8e9e75 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-20147 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. @@ -67,8 +67,10 @@ import org.springframework.util.ClassUtils; public class MethodInvokingBean extends ArgumentConvertingMethodInvoker implements BeanClassLoaderAware, BeanFactoryAware, InitializingBean { + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private ConfigurableBeanFactory beanFactory; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingFactoryBean.java index 1c3c3d9489..8091ed3a51 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/MethodInvokingFactoryBean.java @@ -18,6 +18,7 @@ package org.springframework.beans.factory.config; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; +import org.springframework.lang.Nullable; /** * {@link FactoryBean} which returns a value which is the result of a static or instance @@ -87,6 +88,7 @@ public class MethodInvokingFactoryBean extends MethodInvokingBean implements Fac private boolean initialized = false; /** Method call result in the singleton case */ + @Nullable private Object singletonObject; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/NamedBeanHolder.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/NamedBeanHolder.java index 17ca9c6a96..03981b1232 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/NamedBeanHolder.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/NamedBeanHolder.java @@ -17,7 +17,6 @@ package org.springframework.beans.factory.config; import org.springframework.beans.factory.NamedBean; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -39,7 +38,7 @@ public class NamedBeanHolder implements NamedBean { * @param beanName the name of the bean * @param beanInstance the corresponding bean instance */ - public NamedBeanHolder(String beanName, @Nullable T beanInstance) { + public NamedBeanHolder(String beanName, T beanInstance) { Assert.notNull(beanName, "Bean name must not be null"); this.beanName = beanName; this.beanInstance = beanInstance; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.java index 38f990c8a9..60b684c3d7 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.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.Serializable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -96,6 +97,7 @@ import org.springframework.util.Assert; */ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean> { + @Nullable private String targetBeanName; @@ -124,7 +126,10 @@ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean createInstance() { - return new TargetBeanObjectFactory(getBeanFactory(), this.targetBeanName); + BeanFactory beanFactory = getBeanFactory(); + Assert.state(beanFactory != null, "No BeanFactory available"); + Assert.state(this.targetBeanName != null, "No target bean name specified"); + return new TargetBeanObjectFactory(beanFactory, this.targetBeanName); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java index 91ec753eee..89da05a4a1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.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. @@ -106,16 +106,20 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; /** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */ + @Nullable protected String valueSeparator = DEFAULT_VALUE_SEPARATOR; protected boolean trimValues = false; + @Nullable protected String nullValue; protected boolean ignoreUnresolvablePlaceholders = false; + @Nullable private String beanName; + @Nullable private BeanFactory beanFactory; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PreferencesPlaceholderConfigurer.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PreferencesPlaceholderConfigurer.java index 334699eca6..bfdaea4810 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PreferencesPlaceholderConfigurer.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PreferencesPlaceholderConfigurer.java @@ -45,13 +45,15 @@ import org.springframework.lang.Nullable; */ public class PreferencesPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements InitializingBean { + @Nullable private String systemTreePath; + @Nullable private String userTreePath; - private Preferences systemPrefs; + private Preferences systemPrefs = Preferences.systemRoot(); - private Preferences userPrefs; + private Preferences userPrefs = Preferences.userRoot(); /** @@ -77,10 +79,12 @@ public class PreferencesPlaceholderConfigurer extends PropertyPlaceholderConfigu */ @Override public void afterPropertiesSet() { - this.systemPrefs = (this.systemTreePath != null) ? - Preferences.systemRoot().node(this.systemTreePath) : Preferences.systemRoot(); - this.userPrefs = (this.userTreePath != null) ? - Preferences.userRoot().node(this.userTreePath) : Preferences.userRoot(); + if (this.systemTreePath != null) { + this.systemPrefs = this.systemPrefs.node(this.systemTreePath); + } + if (this.userTreePath != null) { + this.userPrefs = this.userPrefs.node(this.userTreePath); + } } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java index 03617e1a67..0e903911f0 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.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. @@ -27,6 +27,8 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -85,16 +87,22 @@ public class PropertyPathFactoryBean implements FactoryBean, BeanNameAwa private static final Log logger = LogFactory.getLog(PropertyPathFactoryBean.class); + @Nullable private BeanWrapper targetBeanWrapper; + @Nullable private String targetBeanName; + @Nullable private String propertyPath; + @Nullable private Class resultType; + @Nullable private String beanName; + @Nullable private BeanFactory beanFactory; @@ -168,7 +176,7 @@ public class PropertyPathFactoryBean implements FactoryBean, BeanNameAwa } // No other properties specified: check bean name. - int dotIndex = this.beanName.indexOf('.'); + int dotIndex = (this.beanName != null ? this.beanName.indexOf('.') : -1); if (dotIndex == -1) { throw new IllegalArgumentException( "Neither 'targetObject' nor 'targetBeanName' specified, and PropertyPathFactoryBean " + @@ -205,9 +213,12 @@ public class PropertyPathFactoryBean implements FactoryBean, BeanNameAwa } else { // Fetch prototype target bean... + Assert.state(this.beanFactory != null, "No BeanFactory available"); + Assert.state(this.targetBeanName != null, "No target bean name specified"); Object bean = this.beanFactory.getBean(this.targetBeanName); target = PropertyAccessorFactory.forBeanPropertyAccess(bean); } + Assert.state(this.propertyPath != null, "No property path specified"); return target.getPropertyValue(this.propertyPath); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java index 7ec8e77fee..60d1df4997 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.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.inject.Provider; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -41,6 +42,7 @@ import org.springframework.util.Assert; */ public class ProviderCreatingFactoryBean extends AbstractFactoryBean> { + @Nullable private String targetBeanName; @@ -69,7 +71,10 @@ public class ProviderCreatingFactoryBean extends AbstractFactoryBean createInstance() { - return new TargetBeanProvider(getBeanFactory(), this.targetBeanName); + BeanFactory beanFactory = getBeanFactory(); + Assert.state(beanFactory != null, "No BeanFactory available"); + Assert.state(this.targetBeanName != null, "No target bean name specified"); + return new TargetBeanProvider(beanFactory, this.targetBeanName); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanNameReference.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanNameReference.java index 7f40ce0479..798922d68c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanNameReference.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanNameReference.java @@ -33,6 +33,7 @@ public class RuntimeBeanNameReference implements BeanReference { private final String beanName; + @Nullable private Object source; @@ -59,6 +60,7 @@ public class RuntimeBeanNameReference implements BeanReference { } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java index 8a3019b066..258a63c4a1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java @@ -34,6 +34,7 @@ public class RuntimeBeanReference implements BeanReference { private final boolean toParent; + @Nullable private Object source; @@ -84,6 +85,7 @@ public class RuntimeBeanReference implements BeanReference { } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java index 0f0e4b1fa5..2470769042 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java @@ -31,6 +31,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; @@ -189,14 +190,19 @@ import org.springframework.util.StringUtils; */ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFactoryAware, InitializingBean { + @Nullable private Class serviceLocatorInterface; + @Nullable private Constructor serviceLocatorExceptionConstructor; + @Nullable private Properties serviceMappings; + @Nullable private ListableBeanFactory beanFactory; + @Nullable private Object proxy; @@ -278,15 +284,15 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto @SuppressWarnings("unchecked") protected Constructor determineServiceLocatorExceptionConstructor(Class exceptionClass) { try { - return (Constructor) exceptionClass.getConstructor(new Class[] {String.class, Throwable.class}); + return (Constructor) exceptionClass.getConstructor(String.class, Throwable.class); } catch (NoSuchMethodException ex) { try { - return (Constructor) exceptionClass.getConstructor(new Class[] {Throwable.class}); + return (Constructor) exceptionClass.getConstructor(Throwable.class); } catch (NoSuchMethodException ex2) { try { - return (Constructor) exceptionClass.getConstructor(new Class[] {String.class}); + return (Constructor) exceptionClass.getConstructor(String.class); } catch (NoSuchMethodException ex3) { throw new IllegalArgumentException( @@ -354,7 +360,7 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto return System.identityHashCode(proxy); } else if (ReflectionUtils.isToStringMethod(method)) { - return "Service locator: " + serviceLocatorInterface.getName(); + return "Service locator: " + serviceLocatorInterface; } else { return invokeServiceLocatorMethod(method, args); @@ -365,6 +371,7 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto Class serviceLocatorMethodReturnType = getServiceLocatorMethodReturnType(method); try { String beanName = tryGetBeanName(args); + Assert.state(beanFactory != null, "No BeanFactory available"); if (StringUtils.hasLength(beanName)) { // Service locator for a specific bean name return beanFactory.getBean(beanName, serviceLocatorMethodReturnType); @@ -401,6 +408,7 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto } private Class getServiceLocatorMethodReturnType(Method method) throws NoSuchMethodException { + Assert.state(serviceLocatorInterface != null, "No service locator interface specified"); Class[] paramTypes = method.getParameterTypes(); Method interfaceMethod = serviceLocatorInterface.getMethod(method.getName(), paramTypes); Class serviceLocatorReturnType = interfaceMethod.getReturnType(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/SetFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/SetFactoryBean.java index 9c23fe38e2..e38ec4f030 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/SetFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/SetFactoryBean.java @@ -35,9 +35,11 @@ import org.springframework.lang.Nullable; */ public class SetFactoryBean extends AbstractFactoryBean> { + @Nullable private Set sourceSet; @SuppressWarnings("rawtypes") + @Nullable private Class targetSetClass; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java index 303de9c8b3..9f6690ad78 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java @@ -37,12 +37,16 @@ import org.springframework.util.ObjectUtils; */ public class TypedStringValue implements BeanMetadataElement { + @Nullable private String value; + @Nullable private volatile Object targetType; + @Nullable private Object source; + @Nullable private String specifiedTypeName; private volatile boolean dynamic; @@ -157,7 +161,7 @@ public class TypedStringValue implements BeanMetadataElement { * @throws ClassNotFoundException if the type cannot be resolved */ @Nullable - public Class resolveTargetType(ClassLoader classLoader) throws ClassNotFoundException { + public Class resolveTargetType(@Nullable ClassLoader classLoader) throws ClassNotFoundException { String typeName = getTargetTypeName(); if (typeName == null) { return null; @@ -177,6 +181,7 @@ public class TypedStringValue implements BeanMetadataElement { } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java index 3b36eef8ca..38e846a4d9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java @@ -21,6 +21,7 @@ import java.util.Map; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * Factory for a {@code Map} that reads from a YAML source, preserving the @@ -71,6 +72,7 @@ public class YamlMapFactoryBean extends YamlProcessor implements FactoryBean map; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlPropertiesFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlPropertiesFactoryBean.java index 2d7247294b..c4dc698b07 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlPropertiesFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlPropertiesFactoryBean.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. @@ -21,6 +21,7 @@ import java.util.Properties; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.CollectionFactory; +import org.springframework.lang.Nullable; /** * Factory for {@link java.util.Properties} that reads from a YAML source, @@ -82,6 +83,7 @@ public class YamlPropertiesFactoryBean extends YamlProcessor implements FactoryB private boolean singleton = true; + @Nullable private Properties properties; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/AliasDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/AliasDefinition.java index e87d3c5ca9..3eeeba246e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/AliasDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/AliasDefinition.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. @@ -33,6 +33,7 @@ public class AliasDefinition implements BeanMetadataElement { private final String alias; + @Nullable private final Object source; @@ -75,6 +76,7 @@ public class AliasDefinition implements BeanMetadataElement { } @Override + @Nullable public final Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/CompositeComponentDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/CompositeComponentDefinition.java index 299ae7bd6d..6da88b3631 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/CompositeComponentDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/CompositeComponentDefinition.java @@ -35,6 +35,7 @@ public class CompositeComponentDefinition extends AbstractComponentDefinition { private final String name; + @Nullable private final Object source; private final List nestedComponents = new LinkedList<>(); @@ -58,6 +59,7 @@ public class CompositeComponentDefinition extends AbstractComponentDefinition { } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ImportDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ImportDefinition.java index 848af16779..d16ee4c616 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ImportDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/ImportDefinition.java @@ -32,8 +32,10 @@ public class ImportDefinition implements BeanMetadataElement { private final String importedResource; + @Nullable private final Resource[] actualResources; + @Nullable private final Object source; @@ -74,11 +76,13 @@ public class ImportDefinition implements BeanMetadataElement { return this.importedResource; } + @Nullable public final Resource[] getActualResources() { return this.actualResources; } @Override + @Nullable public final Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Location.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Location.java index 23747a032e..924cd49a51 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Location.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Location.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. @@ -37,6 +37,7 @@ public class Location { private final Resource resource; + @Nullable private final Object source; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Problem.java b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Problem.java index 93b07b1ae0..0781337266 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Problem.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/parsing/Problem.java @@ -36,8 +36,10 @@ public class Problem { private final Location location; + @Nullable private final ParseState parseState; + @Nullable private final Throwable rootCause; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/serviceloader/AbstractServiceLoaderBasedFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/serviceloader/AbstractServiceLoaderBasedFactoryBean.java index 483e0dcc68..f4022626fa 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/serviceloader/AbstractServiceLoaderBasedFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/serviceloader/AbstractServiceLoaderBasedFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,8 +35,10 @@ import org.springframework.util.ClassUtils; public abstract class AbstractServiceLoaderBasedFactoryBean extends AbstractFactoryBean implements BeanClassLoaderAware { + @Nullable private Class serviceType; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); @@ -50,6 +52,7 @@ public abstract class AbstractServiceLoaderBasedFactoryBean extends AbstractFact /** * Return the desired service type. */ + @Nullable public Class getServiceType() { return this.serviceType; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 8ecd7f7d14..cb5403f6f1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -125,6 +125,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); /** Resolver strategy for method parameter names */ + @Nullable private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); /** Whether to automatically try to resolve circular references between beans */ @@ -755,13 +756,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac } Class returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( factoryMethod, args, getBeanClassLoader()); - if (returnType != null) { - uniqueCandidate = (commonType == null ? factoryMethod : null); - commonType = ClassUtils.determineCommonAncestor(returnType, commonType); - if (commonType == null) { - // Ambiguous return types found: return null to indicate "not determinable". - return null; - } + uniqueCandidate = (commonType == null ? factoryMethod : null); + commonType = ClassUtils.determineCommonAncestor(returnType, commonType); + if (commonType == null) { + // Ambiguous return types found: return null to indicate "not determinable". + return null; } } catch (Throwable ex) { @@ -869,7 +868,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac */ @Nullable private Class getTypeForFactoryBeanFromMethod(Class beanClass, final String factoryMethodName) { - class Holder { Class value = null; } + class Holder { @Nullable Class value = null; } final Holder objectType = new Holder(); // CGLIB subclass methods hide generic parameters; look at the original user class. @@ -1731,7 +1730,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { - ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); + ClassLoader bcl = getBeanClassLoader(); + if (bcl != null) { + ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); + } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java index 94e169e391..346b11cb27 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java @@ -137,8 +137,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess public static final String INFER_METHOD = "(inferred)"; + @Nullable private volatile Object beanClass; + @Nullable private String scope = SCOPE_DEFAULT; private boolean abstractFlag = false; @@ -149,6 +151,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess private int dependencyCheck = DEPENDENCY_CHECK_NONE; + @Nullable private String[] dependsOn; private boolean autowireCandidate = true; @@ -157,14 +160,17 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess private final Map qualifiers = new LinkedHashMap<>(0); + @Nullable private Supplier instanceSupplier; private boolean nonPublicAccessAllowed = true; private boolean lenientConstructorResolution = true; + @Nullable private String factoryBeanName; + @Nullable private String factoryMethodName; private ConstructorArgumentValues constructorArgumentValues; @@ -173,8 +179,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess private MethodOverrides methodOverrides = new MethodOverrides(); + @Nullable private String initMethodName; + @Nullable private String destroyMethodName; private boolean enforceInitMethod = true; @@ -185,8 +193,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess private int role = BeanDefinition.ROLE_APPLICATION; + @Nullable private String description; + @Nullable private Resource resource; @@ -202,8 +212,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * constructor argument values and property values. */ protected AbstractBeanDefinition(@Nullable ConstructorArgumentValues cargs, @Nullable MutablePropertyValues pvs) { - setConstructorArgumentValues(cargs); - setPropertyValues(pvs); + this.constructorArgumentValues = (cargs != null ? cargs : new ConstructorArgumentValues()); + this.propertyValues = (pvs != null ? pvs : new MutablePropertyValues()); } /** @@ -219,8 +229,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess setLazyInit(original.isLazyInit()); setFactoryBeanName(original.getFactoryBeanName()); setFactoryMethodName(original.getFactoryMethodName()); - setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues())); - setPropertyValues(new MutablePropertyValues(original.getPropertyValues())); + this.constructorArgumentValues = new ConstructorArgumentValues(original.getConstructorArgumentValues()); + this.propertyValues = new MutablePropertyValues(original.getPropertyValues()); setRole(original.getRole()); setSource(original.getSource()); copyAttributesFrom(original); @@ -399,7 +409,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * @throws ClassNotFoundException if the class name could be resolved */ @Nullable - public Class resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException { + public Class resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException { String className = getBeanClassName(); if (className == null) { return null; @@ -428,6 +438,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * Return the name of the target scope for the bean. */ @Override + @Nullable public String getScope() { return this.scope; } @@ -574,6 +585,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * Return the bean names that this bean depends on. */ @Override + @Nullable public String[] getDependsOn() { return this.dependsOn; } @@ -735,6 +747,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * Return the factory bean name, if any. */ @Override + @Nullable public String getFactoryBeanName() { return this.factoryBeanName; } @@ -756,6 +769,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * Return a factory method, if any. */ @Override + @Nullable public String getFactoryMethodName() { return this.factoryMethodName; } @@ -923,6 +937,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * Return a human-readable description of this bean definition. */ @Override + @Nullable public String getDescription() { return this.description; } @@ -931,13 +946,14 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess * Set the resource that this bean definition came from * (for the purpose of showing context in case of errors). */ - public void setResource(Resource resource) { + public void setResource(@Nullable Resource resource) { this.resource = resource; } /** * Return the resource that this bean definition came from. */ + @Nullable public Resource getResource() { return this.resource; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java index 02f45badd9..b552694f2e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java @@ -52,8 +52,10 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable private final BeanDefinitionRegistry registry; + @Nullable private ResourceLoader resourceLoader; + @Nullable private ClassLoader beanClassLoader; private Environment environment; @@ -120,11 +122,12 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable * @see org.springframework.core.io.support.ResourcePatternResolver * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver */ - public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { + public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @Override + @Nullable public ResourceLoader getResourceLoader() { return this.resourceLoader; } @@ -141,6 +144,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable } @Override + @Nullable public ClassLoader getBeanClassLoader() { return this.beanClassLoader; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 6b824d70af..8118772eb2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -113,21 +113,26 @@ import org.springframework.util.StringValueResolver; public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { /** Parent bean factory, for bean inheritance support */ + @Nullable private BeanFactory parentBeanFactory; /** ClassLoader to resolve bean class names with, if necessary */ + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** ClassLoader to temporarily resolve bean class names with, if necessary */ + @Nullable private ClassLoader tempClassLoader; /** Whether to cache bean metadata or rather reobtain it for every access */ private boolean cacheBeanMetadata = true; /** Resolution strategy for expressions in bean definition values */ + @Nullable private BeanExpressionResolver beanExpressionResolver; /** Spring ConversionService to use instead of PropertyEditors */ + @Nullable private ConversionService conversionService; /** Custom PropertyEditorRegistrars to apply to the beans of this factory */ @@ -137,6 +142,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp private final Map, Class> customEditors = new HashMap<>(4); /** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */ + @Nullable private TypeConverter typeConverter; /** String resolvers to apply e.g. to annotation attribute values */ @@ -155,6 +161,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp private final Map scopes = new LinkedHashMap<>(8); /** Security context used when running with a SecurityManager */ + @Nullable private SecurityContextProvider securityContextProvider; /** Map from bean name to merged RootBeanDefinition */ @@ -681,6 +688,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp //--------------------------------------------------------------------- @Override + @Nullable public BeanFactory getParentBeanFactory() { return this.parentBeanFactory; } @@ -711,6 +719,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } @Override + @Nullable public ClassLoader getBeanClassLoader() { return this.beanClassLoader; } @@ -721,6 +730,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } @Override + @Nullable public ClassLoader getTempClassLoader() { return this.tempClassLoader; } @@ -741,6 +751,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } @Override + @Nullable public BeanExpressionResolver getBeanExpressionResolver() { return this.beanExpressionResolver; } @@ -751,6 +762,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } @Override + @Nullable public ConversionService getConversionService() { return this.conversionService; } @@ -1172,7 +1184,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; - if (isCurrentlyInCreation(bce.getBeanName())) { + String bceBeanName = bce.getBeanName(); + if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) { if (logger.isDebugEnabled()) { logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() + "] failed because it tried to obtain currently created bean '" + diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java index f6e29cad61..c18745722a 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java @@ -191,10 +191,11 @@ abstract class AutowireUtils { * @return the resolved target return type or the standard method return type * @since 3.2.5 */ - public static Class resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) { + public static Class resolveReturnTypeForFactoryMethod( + Method method, Object[] args, @Nullable ClassLoader classLoader) { + Assert.notNull(method, "Method must not be null"); Assert.notNull(args, "Argument array must not be null"); - Assert.notNull(classLoader, "ClassLoader must not be null"); TypeVariable[] declaredTypeVariables = method.getTypeParameters(); Type genericReturnType = method.getGenericReturnType(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java index 3a095939ed..b99ce3c9b2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionDefaults.java @@ -33,8 +33,10 @@ public class BeanDefinitionDefaults { private int autowireMode = AbstractBeanDefinition.AUTOWIRE_NO; + @Nullable private String initMethodName; + @Nullable private String destroyMethodName; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java index 7db4a69678..53f00e5e47 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java @@ -194,6 +194,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt */ private static class ClassLoaderAwareGeneratorStrategy extends DefaultGeneratorStrategy { + @Nullable private final ClassLoader classLoader; public ClassLoaderAwareGeneratorStrategy(@Nullable ClassLoader classLoader) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ChildBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ChildBeanDefinition.java index 465a884cd9..0f32ef0eff 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ChildBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ChildBeanDefinition.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. @@ -46,6 +46,7 @@ import org.springframework.util.ObjectUtils; @SuppressWarnings("serial") public class ChildBeanDefinition extends AbstractBeanDefinition { + @Nullable private String parentName; @@ -135,6 +136,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition { } @Override + @Nullable public String getParentName() { return this.parentName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index e06e99470d..917c4c61d4 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -117,7 +117,8 @@ import org.springframework.util.StringUtils; public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { - private static Class javaxInjectProviderClass = null; + @Nullable + private static Class javaxInjectProviderClass; static { try { @@ -126,6 +127,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto } catch (ClassNotFoundException ex) { // JSR-330 API not available - Provider interface simply not supported then. + javaxInjectProviderClass = null; } } @@ -135,6 +137,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto new ConcurrentHashMap<>(8); /** Optional id for this factory, for serialization purposes */ + @Nullable private String serializationId; /** Whether to allow re-registration of a different definition with the same name */ @@ -144,6 +147,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private boolean allowEagerClassLoading = true; /** Optional OrderComparator for dependency Lists and arrays */ + @Nullable private Comparator dependencyComparator; /** Resolver to use for checking if a bean definition is an autowire candidate */ @@ -168,6 +172,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private volatile Set manualSingletonNames = new LinkedHashSet<>(16); /** Cached array of bean definition names in case of frozen configuration */ + @Nullable private volatile String[] frozenBeanDefinitionNames; /** Whether bean definition metadata may be cached for all beans */ @@ -209,6 +214,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto * to be deserialized from this id back into the BeanFactory object, if needed. * @since 4.1.2 */ + @Nullable public String getSerializationId() { return this.serializationId; } @@ -360,8 +366,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @Override public String[] getBeanDefinitionNames() { - if (this.frozenBeanDefinitionNames != null) { - return this.frozenBeanDefinitionNames.clone(); + String[] frozenNames = this.frozenBeanDefinitionNames; + if (frozenNames != null) { + return frozenNames.clone(); } else { return StringUtils.toStringArray(this.beanDefinitionNames); @@ -511,9 +518,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; - if (isCurrentlyInCreation(bce.getBeanName())) { + String exBeanName = bce.getBeanName(); + if (exBeanName != null && isCurrentlyInCreation(exBeanName)) { if (this.logger.isDebugEnabled()) { - this.logger.debug("Ignoring match to currently created bean '" + beanName + "': " + + this.logger.debug("Ignoring match to currently created bean '" + exBeanName + "': " + ex.getMessage()); } onSuppressedException(ex); @@ -1595,6 +1603,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private final boolean optional; + @Nullable private final String beanName; public DependencyObjectProvider(DependencyDescriptor descriptor, @Nullable String beanName) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java index 62da7042a3..52320a452e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java @@ -104,6 +104,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements Collections.newSetFromMap(new ConcurrentHashMap<>(16)); /** List of suppressed Exceptions, available for associating related causes */ + @Nullable private Set suppressedExceptions; /** Flag that indicates whether we're currently within destroySingletons */ diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java index da2572ee8f..5cd65f21b9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java @@ -77,12 +77,16 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { private final boolean nonPublicAccessAllowed; + @Nullable private final AccessControlContext acc; + @Nullable private String destroyMethodName; + @Nullable private transient Method destroyMethod; + @Nullable private List beanPostProcessors; @@ -108,7 +112,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { this.destroyMethodName = destroyMethodName; - this.destroyMethod = determineDestroyMethod(); + this.destroyMethod = determineDestroyMethod(destroyMethodName); if (this.destroyMethod == null) { if (beanDefinition.isEnforceDestroyMethod()) { throw new BeanDefinitionValidationException("Couldn't find a destroy method named '" + @@ -139,7 +143,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { public DisposableBeanAdapter(Object bean, List postProcessors, AccessControlContext acc) { Assert.notNull(bean, "Disposable bean must not be null"); this.bean = bean; - this.beanName = null; + this.beanName = bean.getClass().getName(); this.invokeDisposableBean = (this.bean instanceof DisposableBean); this.nonPublicAccessAllowed = true; this.acc = acc; @@ -150,7 +154,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { * Create a new DisposableBeanAdapter for the given bean. */ private DisposableBeanAdapter(Object bean, String beanName, boolean invokeDisposableBean, - boolean nonPublicAccessAllowed, String destroyMethodName, + boolean nonPublicAccessAllowed, @Nullable String destroyMethodName, @Nullable List postProcessors) { this.bean = bean; @@ -267,7 +271,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { invokeCustomDestroyMethod(this.destroyMethod); } else if (this.destroyMethodName != null) { - Method methodToCall = determineDestroyMethod(); + Method methodToCall = determineDestroyMethod(this.destroyMethodName); if (methodToCall != null) { invokeCustomDestroyMethod(methodToCall); } @@ -276,13 +280,13 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @Nullable - private Method determineDestroyMethod() { + private Method determineDestroyMethod(String name) { try { if (System.getSecurityManager() != null) { - return AccessController.doPrivileged((PrivilegedAction) () -> findDestroyMethod()); + return AccessController.doPrivileged((PrivilegedAction) () -> findDestroyMethod(name)); } else { - return findDestroyMethod(); + return findDestroyMethod(name); } } catch (IllegalArgumentException ex) { @@ -292,10 +296,10 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { } @Nullable - private Method findDestroyMethod() { + private Method findDestroyMethod(String name) { return (this.nonPublicAccessAllowed ? - BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), this.destroyMethodName) : - BeanUtils.findMethodWithMinimalParameters(this.bean.getClass().getMethods(), this.destroyMethodName)); + BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), name) : + BeanUtils.findMethodWithMinimalParameters(this.bean.getClass().getMethods(), name)); } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericBeanDefinition.java index ab404a9e52..7d71d69dab 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericBeanDefinition.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. @@ -39,6 +39,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class GenericBeanDefinition extends AbstractBeanDefinition { + @Nullable private String parentName; @@ -70,6 +71,7 @@ public class GenericBeanDefinition extends AbstractBeanDefinition { } @Override + @Nullable public String getParentName() { return this.parentName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java index 2dbcedf48f..f427a99368 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java @@ -44,6 +44,7 @@ import org.springframework.util.ClassUtils; public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver implements BeanFactoryAware { + @Nullable private BeanFactory beanFactory; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.java index 6fcc4e3f3b..48884c1182 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.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. @@ -33,8 +33,10 @@ import org.springframework.util.ObjectUtils; */ public class LookupOverride extends MethodOverride { + @Nullable private final String beanName; + @Nullable private Method method; @@ -65,6 +67,7 @@ public class LookupOverride extends MethodOverride { /** * Return the name of the bean that should be returned by this method. */ + @Nullable public String getBeanName() { return this.beanName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.java index e47d5dbeb3..0b6e56f5a3 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.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.beans.factory.support; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -29,6 +30,7 @@ import org.springframework.util.Assert; public class ManagedArray extends ManagedList { /** Resolved element type for runtime creation of the target array */ + @Nullable volatile Class resolvedElementType; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedList.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedList.java index a35c413d29..9f0722cb69 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedList.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedList.java @@ -35,8 +35,10 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ManagedList extends ArrayList implements Mergeable, BeanMetadataElement { + @Nullable private Object source; + @Nullable private String elementTypeName; private boolean mergeEnabled; @@ -59,6 +61,7 @@ public class ManagedList extends ArrayList implements Mergeable, BeanMetad } @Override + @Nullable public Object getSource() { return this.source; } @@ -73,6 +76,7 @@ public class ManagedList extends ArrayList implements Mergeable, BeanMetad /** * Return the default element type name (class name) to be used for this list. */ + @Nullable public String getElementTypeName() { return this.elementTypeName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedMap.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedMap.java index ad8682abbe..878bee7ef4 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedMap.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedMap.java @@ -34,10 +34,13 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ManagedMap extends LinkedHashMap implements Mergeable, BeanMetadataElement { + @Nullable private Object source; + @Nullable private String keyTypeName; + @Nullable private String valueTypeName; private boolean mergeEnabled; @@ -60,6 +63,7 @@ public class ManagedMap extends LinkedHashMap implements Mergeable, } @Override + @Nullable public Object getSource() { return this.source; } @@ -74,6 +78,7 @@ public class ManagedMap extends LinkedHashMap implements Mergeable, /** * Return the default key type name (class name) to be used for this map. */ + @Nullable public String getKeyTypeName() { return this.keyTypeName; } @@ -88,6 +93,7 @@ public class ManagedMap extends LinkedHashMap implements Mergeable, /** * Return the default value type name (class name) to be used for this map. */ + @Nullable public String getValueTypeName() { return this.valueTypeName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedProperties.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedProperties.java index ee64afb9e7..f6c8a38352 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedProperties.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedProperties.java @@ -33,6 +33,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ManagedProperties extends Properties implements Mergeable, BeanMetadataElement { + @Nullable private Object source; private boolean mergeEnabled; @@ -47,6 +48,7 @@ public class ManagedProperties extends Properties implements Mergeable, BeanMeta } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedSet.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedSet.java index 24d83e071d..db68abee26 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedSet.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ManagedSet.java @@ -34,8 +34,10 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ManagedSet extends LinkedHashSet implements Mergeable, BeanMetadataElement { + @Nullable private Object source; + @Nullable private String elementTypeName; private boolean mergeEnabled; @@ -58,6 +60,7 @@ public class ManagedSet extends LinkedHashSet implements Mergeable, BeanMe } @Override + @Nullable public Object getSource() { return this.source; } @@ -72,6 +75,7 @@ public class ManagedSet extends LinkedHashSet implements Mergeable, BeanMe /** * Return the default element type name (class name) to be used for this set. */ + @Nullable public String getElementTypeName() { return this.elementTypeName; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/MethodOverride.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/MethodOverride.java index f3a4b36168..74a5373232 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/MethodOverride.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/MethodOverride.java @@ -41,6 +41,7 @@ public abstract class MethodOverride implements BeanMetadataElement { private boolean overloaded = true; + @Nullable private Object source; @@ -88,6 +89,7 @@ public abstract class MethodOverride implements BeanMetadataElement { } @Override + @Nullable public Object getSource() { return this.source; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java index 12a0077e0e..4c2e39757e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/PropertiesBeanDefinitionReader.java @@ -141,6 +141,7 @@ public class PropertiesBeanDefinitionReader extends AbstractBeanDefinitionReader public static final String CONSTRUCTOR_ARG_PREFIX = "$"; + @Nullable private String defaultParentBean; private PropertiesPersister propertiesPersister = new DefaultPropertiesPersister(); @@ -168,13 +169,14 @@ public class PropertiesBeanDefinitionReader extends AbstractBeanDefinitionReader * not apply to a bean definition that carries a class is there for * backwards compatibility reasons. It still matches the typical use case. */ - public void setDefaultParentBean(String defaultParentBean) { + public void setDefaultParentBean(@Nullable String defaultParentBean) { this.defaultParentBean = defaultParentBean; } /** * Return the default parent bean for this bean factory. */ + @Nullable public String getDefaultParentBean() { return this.defaultParentBean; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java index 5a6ba8ec43..66a0ba9ef8 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java @@ -53,35 +53,43 @@ import org.springframework.util.Assert; @SuppressWarnings("serial") public class RootBeanDefinition extends AbstractBeanDefinition { + @Nullable private BeanDefinitionHolder decoratedDefinition; + @Nullable private AnnotatedElement qualifiedElement; boolean allowCaching = true; boolean isFactoryMethodUnique = false; + @Nullable volatile ResolvableType targetType; /** Package-visible field for caching the determined Class of a given bean definition */ + @Nullable volatile Class resolvedTargetType; /** Package-visible field for caching the return type of a generically typed factory method */ + @Nullable volatile ResolvableType factoryMethodReturnType; /** Common lock for the four constructor fields below */ final Object constructorArgumentLock = new Object(); /** Package-visible field for caching the resolved constructor or factory method */ + @Nullable Executable resolvedConstructorOrFactoryMethod; /** Package-visible field that marks the constructor arguments as resolved */ boolean constructorArgumentsResolved = false; /** Package-visible field for caching fully resolved constructor arguments */ + @Nullable Object[] resolvedConstructorArguments; /** Package-visible field for caching partly prepared constructor arguments */ + @Nullable Object[] preparedConstructorArguments; /** Common lock for the two post-processing fields below */ @@ -91,12 +99,16 @@ public class RootBeanDefinition extends AbstractBeanDefinition { boolean postProcessed = false; /** Package-visible field that indicates a before-instantiation post-processor having kicked in */ + @Nullable volatile Boolean beforeInstantiationResolved; + @Nullable private Set externallyManagedConfigMembers; + @Nullable private Set externallyManagedInitMethods; + @Nullable private Set externallyManagedDestroyMethods; @@ -304,7 +316,8 @@ public class RootBeanDefinition extends AbstractBeanDefinition { if (this.resolvedTargetType != null) { return this.resolvedTargetType; } - return (this.targetType != null ? this.targetType.resolve() : null); + ResolvableType targetType = this.targetType; + return (targetType != null ? targetType.resolve() : null); } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java index 8568a321b1..6693851316 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.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. @@ -29,6 +29,7 @@ import org.springframework.lang.Nullable; */ public class SimpleSecurityContextProvider implements SecurityContextProvider { + @Nullable private final AccessControlContext acc; 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 2e296e27ec..601b06b34a 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 @@ -52,8 +52,10 @@ public class BeanConfigurerSupport implements BeanFactoryAware, InitializingBean /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private volatile BeanWiringInfoResolver beanWiringInfoResolver; + @Nullable private volatile ConfigurableListableBeanFactory beanFactory; @@ -130,29 +132,35 @@ public class BeanConfigurerSupport implements BeanFactoryAware, InitializingBean return; } - BeanWiringInfo bwi = this.beanWiringInfoResolver.resolveWiringInfo(beanInstance); + BeanWiringInfoResolver bwiResolver = this.beanWiringInfoResolver; + Assert.state(bwiResolver != null, "No BeanWiringInfoResolver available"); + BeanWiringInfo bwi = bwiResolver.resolveWiringInfo(beanInstance); if (bwi == null) { // Skip the bean if no wiring info given. return; } + + ConfigurableListableBeanFactory beanFactory = this.beanFactory; + Assert.state(beanFactory != null, "No BeanFactory available"); try { if (bwi.indicatesAutowiring() || (bwi.isDefaultBeanName() && bwi.getBeanName() != null && - !this.beanFactory.containsBean(bwi.getBeanName()))) { + !beanFactory.containsBean(bwi.getBeanName()))) { // Perform autowiring (also applying standard factory / post-processor callbacks). - this.beanFactory.autowireBeanProperties(beanInstance, bwi.getAutowireMode(), bwi.getDependencyCheck()); - this.beanFactory.initializeBean(beanInstance, bwi.getBeanName()); + beanFactory.autowireBeanProperties(beanInstance, bwi.getAutowireMode(), bwi.getDependencyCheck()); + beanFactory.initializeBean(beanInstance, bwi.getBeanName()); } else { // Perform explicit wiring based on the specified bean definition. - this.beanFactory.configureBean(beanInstance, bwi.getBeanName()); + beanFactory.configureBean(beanInstance, bwi.getBeanName()); } } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; - if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) { + String bceBeanName = bce.getBeanName(); + if (bceBeanName != null && beanFactory.isCurrentlyInCreation(bceBeanName)) { if (logger.isDebugEnabled()) { logger.debug("Failed to create target bean '" + bce.getBeanName() + "' while configuring object of type [" + beanInstance.getClass().getName() + diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanWiringInfo.java b/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanWiringInfo.java index eaeafb220e..c01f75f34e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanWiringInfo.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/wiring/BeanWiringInfo.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. @@ -49,7 +49,8 @@ public class BeanWiringInfo { public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; - private String beanName = null; + @Nullable + private String beanName; private boolean isDefaultBeanName = false; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java index 757482cd3a..be89285025 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java @@ -18,6 +18,7 @@ package org.springframework.beans.factory.xml; import org.w3c.dom.Element; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.lang.Nullable; @@ -75,9 +76,10 @@ public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDef } } builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); - if (parserContext.isNested()) { + BeanDefinition containingBd = parserContext.getContainingBeanDefinition(); + if (containingBd != null) { // Inner bean definition must receive same scope as containing bean. - String scopeName = parserContext.getContainingBeanDefinition().getScope(); + String scopeName = containingBd.getScope(); if (scopeName != null) { builder.setScope(scopeName); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.java index 64540fe751..24744dc794 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.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. @@ -59,12 +59,14 @@ public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver protected final Log logger = LogFactory.getLog(getClass()); /** ClassLoader to use for NamespaceHandler classes */ + @Nullable private final ClassLoader classLoader; /** Resource location to search for */ private final String handlerMappingsLocation; /** Stores the mappings from namespace URI to NamespaceHandler class name / instance */ + @Nullable private volatile Map handlerMappings; @@ -148,17 +150,20 @@ public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver * Load the specified NamespaceHandler mappings lazily. */ private Map getHandlerMappings() { - if (this.handlerMappings == null) { + Map handlerMappings = this.handlerMappings; + if (handlerMappings == null) { synchronized (this) { - if (this.handlerMappings == null) { + handlerMappings = this.handlerMappings; + if (handlerMappings == null) { try { Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded NamespaceHandler mappings: " + mappings); } - Map handlerMappings = new ConcurrentHashMap<>(mappings.size()); - CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); + Map mappingsToUse = new ConcurrentHashMap<>(mappings.size()); + CollectionUtils.mergePropertiesIntoMap(mappings, mappingsToUse); + handlerMappings = mappingsToUse; this.handlerMappings = handlerMappings; } catch (IOException ex) { @@ -168,7 +173,7 @@ public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver } } } - return this.handlerMappings; + return handlerMappings; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/DocumentDefaultsDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/DocumentDefaultsDefinition.java index 6fbb349656..3558676799 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/DocumentDefaultsDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/DocumentDefaultsDefinition.java @@ -29,18 +29,25 @@ import org.springframework.lang.Nullable; */ public class DocumentDefaultsDefinition implements DefaultsDefinition { + @Nullable private String lazyInit; + @Nullable private String merge; + @Nullable private String autowire; + @Nullable private String autowireCandidates; + @Nullable private String initMethod; + @Nullable private String destroyMethod; + @Nullable private Object source; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java index 9ef1709d24..a27ebd487b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.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. @@ -43,6 +43,7 @@ public final class ParserContext { private final BeanDefinitionParserDelegate delegate; + @Nullable private BeanDefinition containingBeanDefinition; private final Stack containingComponents = new Stack<>(); @@ -74,6 +75,7 @@ public final class ParserContext { return this.delegate; } + @Nullable public final BeanDefinition getContainingBeanDefinition() { return this.containingBeanDefinition; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java index 660257cb69..a443aa1264 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java @@ -66,11 +66,13 @@ public class PluggableSchemaResolver implements EntityResolver { private static final Log logger = LogFactory.getLog(PluggableSchemaResolver.class); + @Nullable private final ClassLoader classLoader; private final String schemaMappingsLocation; /** Stores the mapping of schema URL -> local schema path */ + @Nullable private volatile Map schemaMappings; @@ -136,9 +138,11 @@ public class PluggableSchemaResolver implements EntityResolver { * Load the specified schema mappings lazily. */ private Map getSchemaMappings() { - if (this.schemaMappings == null) { + Map schemaMappings = this.schemaMappings; + if (schemaMappings == null) { synchronized (this) { - if (this.schemaMappings == null) { + schemaMappings = this.schemaMappings; + if (schemaMappings == null) { if (logger.isDebugEnabled()) { logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]"); } @@ -148,8 +152,9 @@ public class PluggableSchemaResolver implements EntityResolver { if (logger.isDebugEnabled()) { logger.debug("Loaded schema mappings: " + mappings); } - Map schemaMappings = new ConcurrentHashMap<>(mappings.size()); - CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings); + Map mappingsToUse = new ConcurrentHashMap<>(mappings.size()); + CollectionUtils.mergePropertiesIntoMap(mappings, mappingsToUse); + schemaMappings = mappingsToUse; this.schemaMappings = schemaMappings; } catch (IOException ex) { @@ -159,7 +164,7 @@ public class PluggableSchemaResolver implements EntityResolver { } } } - return this.schemaMappings; + return schemaMappings; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java index 48b30cc6d2..8832fd045b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java @@ -113,10 +113,12 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { private SourceExtractor sourceExtractor = new NullSourceExtractor(); + @Nullable private NamespaceHandlerResolver namespaceHandlerResolver; private DocumentLoader documentLoader = new DefaultDocumentLoader(); + @Nullable private EntityResolver entityResolver; private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger); diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassArrayEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassArrayEditor.java index bcc1a90a6d..0e07928aff 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassArrayEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassArrayEditor.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. @@ -37,6 +37,7 @@ import org.springframework.util.StringUtils; */ public class ClassArrayEditor extends PropertyEditorSupport { + @Nullable private final ClassLoader classLoader; diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassEditor.java index fcff9ad064..c2d8861fd9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ClassEditor.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. @@ -38,6 +38,7 @@ import org.springframework.util.StringUtils; */ public class ClassEditor extends PropertyEditorSupport { + @Nullable private final ClassLoader classLoader; diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomBooleanEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomBooleanEditor.java index ed0e513ac3..79ee544bc7 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomBooleanEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomBooleanEditor.java @@ -51,8 +51,10 @@ public class CustomBooleanEditor extends PropertyEditorSupport { public static final String VALUE_0 = "0"; + @Nullable private final String trueString; + @Nullable private final String falseString; private final boolean allowEmpty; diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomNumberEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomNumberEditor.java index aad392d15c..2b62981627 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomNumberEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomNumberEditor.java @@ -47,6 +47,7 @@ public class CustomNumberEditor extends PropertyEditorSupport { private final Class numberClass; + @Nullable private final NumberFormat numberFormat; private final boolean allowEmpty; diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java index 5d88f30b33..c8c26ced2d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java @@ -44,6 +44,7 @@ public class StringArrayPropertyEditor extends PropertyEditorSupport { private final String separator; + @Nullable private final String charsToDelete; private final boolean emptyArrayAsNull; diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringTrimmerEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringTrimmerEditor.java index cb1cd0e13b..8bd512cbd3 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringTrimmerEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringTrimmerEditor.java @@ -32,6 +32,7 @@ import org.springframework.util.StringUtils; */ public class StringTrimmerEditor extends PropertyEditorSupport { + @Nullable private final String charsToDelete; private final boolean emptyAsNull; diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java index 56537ca955..d9609694bb 100644 --- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java +++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.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,6 +50,7 @@ import org.springframework.util.StringUtils; */ public class URIEditor extends PropertyEditorSupport { + @Nullable private final ClassLoader classLoader; private final boolean encode; diff --git a/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java b/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java index 84e854d90e..e6108f38f6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java +++ b/spring-beans/src/main/java/org/springframework/beans/support/ArgumentConvertingMethodInvoker.java @@ -41,6 +41,7 @@ import org.springframework.util.ReflectionUtils; */ public class ArgumentConvertingMethodInvoker extends MethodInvoker { + @Nullable private TypeConverter typeConverter; private boolean useDefaultConverter = true; diff --git a/spring-beans/src/main/java/org/springframework/beans/support/PagedListHolder.java b/spring-beans/src/main/java/org/springframework/beans/support/PagedListHolder.java index d22b26ae0b..9f4b9f8234 100644 --- a/spring-beans/src/main/java/org/springframework/beans/support/PagedListHolder.java +++ b/spring-beans/src/main/java/org/springframework/beans/support/PagedListHolder.java @@ -18,6 +18,7 @@ package org.springframework.beans.support; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -56,12 +57,15 @@ public class PagedListHolder implements Serializable { public static final int DEFAULT_MAX_LINKED_PAGES = 10; - private List source; + private List source = Collections.emptyList(); + @Nullable private Date refreshDate; + @Nullable private SortDefinition sort; + @Nullable private SortDefinition sortUsed; private int pageSize = DEFAULT_PAGE_SIZE; diff --git a/spring-beans/src/main/java/org/springframework/beans/support/PropertyComparator.java b/spring-beans/src/main/java/org/springframework/beans/support/PropertyComparator.java index 6eb876a3c1..55ac70efdf 100644 --- a/spring-beans/src/main/java/org/springframework/beans/support/PropertyComparator.java +++ b/spring-beans/src/main/java/org/springframework/beans/support/PropertyComparator.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. @@ -135,7 +135,7 @@ public class PropertyComparator implements Comparator { */ public static void sort(List source, SortDefinition sortDefinition) throws BeansException { if (StringUtils.hasText(sortDefinition.getProperty())) { - Collections.sort(source, new PropertyComparator(sortDefinition)); + Collections.sort(source, new PropertyComparator<>(sortDefinition)); } } diff --git a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java index 32eb2c503e..f7be4ea94e 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java +++ b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCache.java @@ -129,6 +129,7 @@ public class CaffeineCache extends AbstractValueAdaptingCache { private class PutIfAbsentFunction implements Function { + @Nullable private final Object value; private boolean called; diff --git a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java index 144ef388c7..a886df6b09 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java +++ b/spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java @@ -61,6 +61,7 @@ public class CaffeineCacheManager implements CacheManager { private Caffeine cacheBuilder = Caffeine.newBuilder(); + @Nullable private CacheLoader cacheLoader; private boolean allowNullValues = true; diff --git a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java index 429fefefeb..a18910b644 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheFactoryBean.java @@ -36,6 +36,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * {@link FactoryBean} that creates a named EhCache {@link net.sf.ehcache.Cache} instance @@ -63,20 +64,26 @@ public class EhCacheFactoryBean extends CacheConfiguration implements FactoryBea protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private CacheManager cacheManager; private boolean blocking = false; + @Nullable private CacheEntryFactory cacheEntryFactory; + @Nullable private BootstrapCacheLoader bootstrapCacheLoader; + @Nullable private Set cacheEventListeners; private boolean disabled = false; + @Nullable private String beanName; + @Nullable private Ehcache cache; diff --git a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java index 3440321c02..bc760edfdb 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.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. @@ -27,6 +27,7 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; /** * {@link FactoryBean} that exposes an EhCache {@link net.sf.ehcache.CacheManager} @@ -55,14 +56,17 @@ public class EhCacheManagerFactoryBean implements FactoryBean, Ini protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private Resource configLocation; + @Nullable private String cacheManagerName; private boolean acceptExisting = false; private boolean shared = false; + @Nullable private CacheManager cacheManager; private boolean locallyManaged = true; @@ -182,7 +186,7 @@ public class EhCacheManagerFactoryBean implements FactoryBean, Ini @Override public void destroy() { - if (this.locallyManaged) { + if (this.cacheManager != null && this.locallyManaged) { if (logger.isInfoEnabled()) { logger.info("Shutting down EhCache CacheManager" + (this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : "")); diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheManagerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheManagerFactoryBean.java index 1b58aa9da3..8408d21877 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheManagerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheManagerFactoryBean.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. @@ -42,12 +42,16 @@ import org.springframework.lang.Nullable; public class JCacheManagerFactoryBean implements FactoryBean, BeanClassLoaderAware, InitializingBean, DisposableBean { + @Nullable private URI cacheManagerUri; + @Nullable private Properties cacheManagerProperties; + @Nullable private ClassLoader beanClassLoader; + @Nullable private CacheManager cacheManager; @@ -98,7 +102,9 @@ public class JCacheManagerFactoryBean @Override public void destroy() { - this.cacheManager.close(); + if (this.cacheManager != null) { + this.cacheManager.close(); + } } } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/ProxyJCacheConfiguration.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/ProxyJCacheConfiguration.java index 028a6ccfb6..d581e8d264 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/ProxyJCacheConfiguration.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/ProxyJCacheConfiguration.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. @@ -45,7 +45,9 @@ public class ProxyJCacheConfiguration extends AbstractJCacheConfiguration { new BeanFactoryJCacheOperationSourceAdvisor(); advisor.setCacheOperationSource(cacheOperationSource()); advisor.setAdvice(cacheInterceptor()); - advisor.setOrder(this.enableCaching.getNumber("order")); + if (this.enableCaching != null) { + advisor.setOrder(this.enableCaching.getNumber("order")); + } return advisor; } diff --git a/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheManagerProxy.java b/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheManagerProxy.java index 80a4018bb9..e56f69d282 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheManagerProxy.java +++ b/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheManagerProxy.java @@ -21,6 +21,7 @@ import java.util.Collection; import org.springframework.beans.factory.InitializingBean; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -38,6 +39,7 @@ import org.springframework.util.Assert; */ public class TransactionAwareCacheManagerProxy implements CacheManager, InitializingBean { + @Nullable private CacheManager targetCacheManager; @@ -75,12 +77,14 @@ public class TransactionAwareCacheManagerProxy implements CacheManager, Initiali @Override public Cache getCache(String name) { + Assert.state(this.targetCacheManager != null, "No target CacheManager set"); Cache targetCache = this.targetCacheManager.getCache(name); return (targetCache != null ? new TransactionAwareCacheDecorator(targetCache) : null); } @Override public Collection getCacheNames() { + Assert.state(this.targetCacheManager != null, "No target CacheManager set"); return this.targetCacheManager.getCacheNames(); } diff --git a/spring-context-support/src/main/java/org/springframework/mail/MailSendException.java b/spring-context-support/src/main/java/org/springframework/mail/MailSendException.java index bc8816d4b2..5b7fd6e050 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/MailSendException.java +++ b/spring-context-support/src/main/java/org/springframework/mail/MailSendException.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. @@ -36,6 +36,7 @@ public class MailSendException extends MailException { private transient final Map failedMessages; + @Nullable private Exception[] messageExceptions; diff --git a/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java b/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java index 7c01ae40b9..90d75cf7c4 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java +++ b/spring-context-support/src/main/java/org/springframework/mail/SimpleMailMessage.java @@ -43,20 +43,28 @@ import org.springframework.util.StringUtils; @SuppressWarnings("serial") public class SimpleMailMessage implements MailMessage, Serializable { + @Nullable private String from; + @Nullable private String replyTo; + @Nullable private String[] to; + @Nullable private String[] cc; + @Nullable private String[] bcc; + @Nullable private Date sentDate; + @Nullable private String subject; + @Nullable private String text; diff --git a/spring-context-support/src/main/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMap.java b/spring-context-support/src/main/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMap.java index 75761a38e7..65dd07f849 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMap.java +++ b/spring-context-support/src/main/java/org/springframework/mail/javamail/ConfigurableMimeFileTypeMap.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. @@ -69,12 +69,14 @@ public class ConfigurableMimeFileTypeMap extends FileTypeMap implements Initiali /** * Used to configure additional mappings. */ + @Nullable private String[] mappings; /** * The delegate FileTypeMap, compiled from the mappings in the mapping file * and the entries in the {@code mappings} property. */ + @Nullable private FileTypeMap fileTypeMap; diff --git a/spring-context-support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java b/spring-context-support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java index ef7c335d69..4d8c220f78 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java +++ b/spring-context-support/src/main/java/org/springframework/mail/javamail/JavaMailSenderImpl.java @@ -79,18 +79,24 @@ public class JavaMailSenderImpl implements JavaMailSender { private Properties javaMailProperties = new Properties(); + @Nullable private Session session; + @Nullable private String protocol; + @Nullable private String host; private int port = DEFAULT_PORT; + @Nullable private String username; + @Nullable private String password; + @Nullable private String defaultEncoding; private FileTypeMap defaultFileTypeMap; diff --git a/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java b/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java index 71ea6d672a..7253251fbf 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java +++ b/spring-context-support/src/main/java/org/springframework/mail/javamail/MimeMessageHelper.java @@ -163,10 +163,13 @@ public class MimeMessageHelper { private final MimeMessage mimeMessage; + @Nullable private MimeMultipart rootMimeMultipart; + @Nullable private MimeMultipart mimeMultipart; + @Nullable private final String encoding; private FileTypeMap fileTypeMap; @@ -376,17 +379,6 @@ public class MimeMessageHelper { return (this.rootMimeMultipart != null); } - /** - * Throw an IllegalStateException if this helper is not in multipart mode. - */ - private void checkMultipart() throws IllegalStateException { - if (!isMultipart()) { - throw new IllegalStateException("Not in multipart mode - " + - "create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " + - "if you need to set alternative texts or add inline elements or attachments."); - } - } - /** * Return the root MIME "multipart/mixed" object, if any. * Can be used to manually add attachments. @@ -398,7 +390,11 @@ public class MimeMessageHelper { * @see javax.mail.internet.MimeMultipart#addBodyPart */ public final MimeMultipart getRootMimeMultipart() throws IllegalStateException { - checkMultipart(); + if (this.rootMimeMultipart == null) { + throw new IllegalStateException("Not in multipart mode - " + + "create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " + + "if you need to set alternative texts or add inline elements or attachments."); + } return this.rootMimeMultipart; } @@ -413,7 +409,11 @@ public class MimeMessageHelper { * @see javax.mail.internet.MimeMultipart#addBodyPart */ public final MimeMultipart getMimeMultipart() throws IllegalStateException { - checkMultipart(); + if (this.mimeMultipart == null) { + throw new IllegalStateException("Not in multipart mode - " + + "create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " + + "if you need to set alternative texts or add inline elements or attachments."); + } return this.mimeMultipart; } diff --git a/spring-context-support/src/main/java/org/springframework/mail/javamail/SmartMimeMessage.java b/spring-context-support/src/main/java/org/springframework/mail/javamail/SmartMimeMessage.java index d17a10ab95..01d7ee5e91 100644 --- a/spring-context-support/src/main/java/org/springframework/mail/javamail/SmartMimeMessage.java +++ b/spring-context-support/src/main/java/org/springframework/mail/javamail/SmartMimeMessage.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. @@ -39,8 +39,10 @@ import org.springframework.lang.Nullable; */ class SmartMimeMessage extends MimeMessage { + @Nullable private final String defaultEncoding; + @Nullable private final FileTypeMap defaultFileTypeMap; @@ -50,7 +52,9 @@ class SmartMimeMessage extends MimeMessage { * @param defaultEncoding the default encoding, or {@code null} if none * @param defaultFileTypeMap the default FileTypeMap, or {@code null} if none */ - public SmartMimeMessage(Session session, @Nullable String defaultEncoding, @Nullable FileTypeMap defaultFileTypeMap) { + public SmartMimeMessage( + Session session, @Nullable String defaultEncoding, @Nullable FileTypeMap defaultFileTypeMap) { + super(session); this.defaultEncoding = defaultEncoding; this.defaultFileTypeMap = defaultFileTypeMap; diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java index 2274fe046f..80baf2794d 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java @@ -38,8 +38,10 @@ import org.springframework.util.Assert; public abstract class TimerManagerAccessor extends JndiLocatorSupport implements InitializingBean, DisposableBean, Lifecycle { + @Nullable private TimerManager timerManager; + @Nullable private String timerManagerName; private boolean shared = false; @@ -139,7 +141,7 @@ public abstract class TimerManagerAccessor extends JndiLocatorSupport @Override public void start() { if (!this.shared) { - this.timerManager.resume(); + obtainTimerManager().resume(); } } @@ -150,7 +152,7 @@ public abstract class TimerManagerAccessor extends JndiLocatorSupport @Override public void stop() { if (!this.shared) { - this.timerManager.suspend(); + obtainTimerManager().suspend(); } } @@ -162,7 +164,8 @@ public abstract class TimerManagerAccessor extends JndiLocatorSupport */ @Override public boolean isRunning() { - return (!this.timerManager.isSuspending() && !this.timerManager.isStopping()); + TimerManager tm = obtainTimerManager(); + return (!tm.isSuspending() && !tm.isStopping()); } @@ -177,7 +180,7 @@ public abstract class TimerManagerAccessor extends JndiLocatorSupport @Override public void destroy() { // Stop the entire TimerManager, if necessary. - if (!this.shared) { + if (this.timerManager != null && !this.shared) { // May return early, but at least we already cancelled all known Timers. this.timerManager.stop(); } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java index bdc7b83b47..a1fe4568e3 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.Lifecycle; +import org.springframework.lang.Nullable; /** * {@link org.springframework.beans.factory.FactoryBean} that retrieves a @@ -54,6 +55,7 @@ import org.springframework.context.Lifecycle; public class TimerManagerFactoryBean extends TimerManagerAccessor implements FactoryBean, InitializingBean, DisposableBean, Lifecycle { + @Nullable private ScheduledTimerListener[] scheduledTimerListeners; private final List timers = new LinkedList<>(); @@ -79,6 +81,7 @@ public class TimerManagerFactoryBean extends TimerManagerAccessor @Override public void afterPropertiesSet() throws NamingException { super.afterPropertiesSet(); + if (this.scheduledTimerListeners != null) { TimerManager timerManager = obtainTimerManager(); for (ScheduledTimerListener scheduledTask : this.scheduledTimerListeners) { diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java index e5b647cfe5..aabe2226a5 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java @@ -30,6 +30,7 @@ import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.support.SimpleTriggerContext; import org.springframework.scheduling.support.TaskUtils; +import org.springframework.util.Assert; import org.springframework.util.ErrorHandler; /** @@ -42,6 +43,7 @@ import org.springframework.util.ErrorHandler; */ public class TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler { + @Nullable private volatile ErrorHandler errorHandler; @@ -108,6 +110,7 @@ public class TimerManagerTaskScheduler extends TimerManagerAccessor implements T */ private static class TimerScheduledFuture extends FutureTask implements TimerListener, ScheduledFuture { + @Nullable protected transient Timer timer; protected transient boolean cancelled = false; @@ -128,13 +131,16 @@ public class TimerManagerTaskScheduler extends TimerManagerAccessor implements T @Override public boolean cancel(boolean mayInterruptIfRunning) { boolean result = super.cancel(mayInterruptIfRunning); - this.timer.cancel(); + if (this.timer != null) { + this.timer.cancel(); + } this.cancelled = true; return result; } @Override public long getDelay(TimeUnit unit) { + Assert.state(this.timer != null, "No Timer available"); return unit.convert(this.timer.getScheduledExecutionTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @@ -158,7 +164,7 @@ public class TimerManagerTaskScheduler extends TimerManagerAccessor implements T private final SimpleTriggerContext triggerContext = new SimpleTriggerContext(); - private volatile Date scheduledExecutionTime; + private volatile Date scheduledExecutionTime = new Date(); public ReschedulingTimerListener(Runnable runnable, Trigger trigger) { super(runnable); @@ -167,10 +173,11 @@ public class TimerManagerTaskScheduler extends TimerManagerAccessor implements T @Nullable public ScheduledFuture schedule() { - this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext); - if (this.scheduledExecutionTime == null) { + Date nextExecutionTime = this.trigger.nextExecutionTime(this.triggerContext); + if (nextExecutionTime == null) { return null; } + this.scheduledExecutionTime = nextExecutionTime; setTimer(obtainTimerManager().schedule(this, this.scheduledExecutionTime)); return this; } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java index 90d30aa48a..ed2059f3af 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.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. @@ -34,6 +34,7 @@ import org.springframework.core.task.AsyncListenableTaskExecutor; import org.springframework.core.task.TaskDecorator; import org.springframework.core.task.TaskRejectedException; import org.springframework.jndi.JndiLocatorSupport; +import org.springframework.lang.Nullable; import org.springframework.scheduling.SchedulingException; import org.springframework.scheduling.SchedulingTaskExecutor; import org.springframework.util.Assert; @@ -66,12 +67,16 @@ import org.springframework.util.concurrent.ListenableFutureTask; public class WorkManagerTaskExecutor extends JndiLocatorSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, WorkManager, InitializingBean { + @Nullable private WorkManager workManager; + @Nullable private String workManagerName; + @Nullable private WorkListener workListener; + @Nullable private TaskDecorator taskDecorator; @@ -128,6 +133,11 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport } } + private WorkManager obtainWorkManager() { + Assert.state(this.workManager != null, "No WorkManager specified"); + return this.workManager; + } + //------------------------------------------------------------------------- // Implementation of the Spring SchedulingTaskExecutor interface @@ -135,14 +145,13 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @Override public void execute(Runnable task) { - Assert.state(this.workManager != null, "No WorkManager specified"); Work work = new DelegatingWork(this.taskDecorator != null ? this.taskDecorator.decorate(task) : task); try { if (this.workListener != null) { - this.workManager.schedule(work, this.workListener); + obtainWorkManager().schedule(work, this.workListener); } else { - this.workManager.schedule(work); + obtainWorkManager().schedule(work); } } catch (WorkRejectedException ex) { @@ -201,24 +210,24 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @Override public WorkItem schedule(Work work) throws WorkException, IllegalArgumentException { - return this.workManager.schedule(work); + return obtainWorkManager().schedule(work); } @Override public WorkItem schedule(Work work, WorkListener workListener) throws WorkException { - return this.workManager.schedule(work, workListener); + return obtainWorkManager().schedule(work, workListener); } @Override @SuppressWarnings("rawtypes") public boolean waitForAll(Collection workItems, long timeout) throws InterruptedException { - return this.workManager.waitForAll(workItems, timeout); + return obtainWorkManager().waitForAll(workItems, timeout); } @Override @SuppressWarnings("rawtypes") public Collection waitForAny(Collection workItems, long timeout) throws InterruptedException { - return this.workManager.waitForAny(workItems, timeout); + return obtainWorkManager().waitForAny(workItems, timeout); } } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/CronTriggerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/CronTriggerFactoryBean.java index 03917ad577..41ddc93160 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/CronTriggerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/CronTriggerFactoryBean.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.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.Constants; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -61,32 +62,42 @@ public class CronTriggerFactoryBean implements FactoryBean, BeanNam private static final Constants constants = new Constants(CronTrigger.class); + @Nullable private String name; + @Nullable private String group; + @Nullable private JobDetail jobDetail; private JobDataMap jobDataMap = new JobDataMap(); + @Nullable private Date startTime; private long startDelay = 0; + @Nullable private String cronExpression; + @Nullable private TimeZone timeZone; + @Nullable private String calendarName; private int priority; private int misfireInstruction; + @Nullable private String description; + @Nullable private String beanName; + @Nullable private CronTrigger cronTrigger; @@ -218,6 +229,8 @@ public class CronTriggerFactoryBean implements FactoryBean, BeanNam @Override public void afterPropertiesSet() throws ParseException { + Assert.notNull(this.cronExpression, "Property 'cronExpression' is required"); + if (this.name == null) { this.name = this.beanName; } @@ -235,7 +248,7 @@ public class CronTriggerFactoryBean implements FactoryBean, BeanNam } CronTriggerImpl cti = new CronTriggerImpl(); - cti.setName(this.name); + cti.setName(this.name != null ? this.name : toString()); cti.setGroup(this.group); if (this.jobDetail != null) { cti.setJobKey(this.jobDetail.getKey()); diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/JobDetailFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/JobDetailFactoryBean.java index 50167a9012..01c7921054 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/JobDetailFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/JobDetailFactoryBean.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. @@ -18,6 +18,7 @@ package org.springframework.scheduling.quartz; import java.util.Map; +import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.Scheduler; @@ -28,6 +29,8 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.JobDetail} @@ -47,11 +50,14 @@ import org.springframework.context.ApplicationContextAware; public class JobDetailFactoryBean implements FactoryBean, BeanNameAware, ApplicationContextAware, InitializingBean { + @Nullable private String name; + @Nullable private String group; - private Class jobClass; + @Nullable + private Class jobClass; private JobDataMap jobDataMap = new JobDataMap(); @@ -59,14 +65,19 @@ public class JobDetailFactoryBean private boolean requestsRecovery = false; + @Nullable private String description; + @Nullable private String beanName; + @Nullable private ApplicationContext applicationContext; + @Nullable private String applicationContextJobDataKey; + @Nullable private JobDetail jobDetail; @@ -87,7 +98,7 @@ public class JobDetailFactoryBean /** * Specify the job's implementation class. */ - public void setJobClass(Class jobClass) { + public void setJobClass(Class jobClass) { this.jobClass = jobClass; } @@ -176,8 +187,9 @@ public class JobDetailFactoryBean @Override - @SuppressWarnings("unchecked") public void afterPropertiesSet() { + Assert.notNull(this.jobClass, "Property 'jobClass' is required"); + if (this.name == null) { this.name = this.beanName; } @@ -194,9 +206,9 @@ public class JobDetailFactoryBean } JobDetailImpl jdi = new JobDetailImpl(); - jdi.setName(this.name); + jdi.setName(this.name != null ? this.name : toString()); jdi.setGroup(this.group); - jdi.setJobClass((Class) this.jobClass); + jdi.setJobClass(this.jobClass); jdi.setJobDataMap(this.jobDataMap); jdi.setDurability(this.durability); jdi.setRequestsRecovery(this.requestsRecovery); diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java index c51b2c0054..b8454fe8dc 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.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. @@ -31,6 +31,7 @@ import org.quartz.utils.DBConnectionManager; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.MetaDataAccessException; +import org.springframework.lang.Nullable; /** * Subclass of Quartz's JobStoreCMT class that delegates to a Spring-managed @@ -78,6 +79,7 @@ public class LocalDataSourceJobStore extends JobStoreCMT { public static final String NON_TX_DATA_SOURCE_PREFIX = "springNonTxDataSource."; + @Nullable private DataSource dataSource; diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java index 59855d4052..d00c5ce6c8 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalTaskExecutorThreadPool.java @@ -24,6 +24,9 @@ import org.apache.commons.logging.LogFactory; import org.quartz.SchedulerConfigException; import org.quartz.spi.ThreadPool; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + /** * Quartz ThreadPool adapter that delegates to a Spring-managed * TaskExecutor instance, specified on SchedulerFactoryBean. @@ -37,6 +40,7 @@ public class LocalTaskExecutorThreadPool implements ThreadPool { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private Executor taskExecutor; @@ -72,6 +76,7 @@ public class LocalTaskExecutorThreadPool implements ThreadPool { @Override public boolean runInThread(Runnable runnable) { + Assert.state(this.taskExecutor != null, "No TaskExecutor available"); try { this.taskExecutor.execute(runnable); return true; diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java index f4bd8956dc..de36084c92 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java @@ -35,6 +35,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.support.ArgumentConvertingMethodInvoker; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MethodInvoker; @@ -76,20 +77,26 @@ import org.springframework.util.MethodInvoker; public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethodInvoker implements FactoryBean, BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean { + @Nullable private String name; private String group = Scheduler.DEFAULT_GROUP; private boolean concurrent = true; + @Nullable private String targetBeanName; + @Nullable private String beanName; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private BeanFactory beanFactory; + @Nullable private JobDetail jobDetail; @@ -169,7 +176,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod // Build JobDetail instance. JobDetailImpl jdi = new JobDetailImpl(); - jdi.setName(name); + jdi.setName(name != null ? name : toString()); jdi.setGroup(this.group); jdi.setJobClass((Class) jobClass); jdi.setDurability(true); @@ -239,6 +246,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod protected static final Log logger = LogFactory.getLog(MethodInvokingJob.class); + @Nullable private MethodInvoker methodInvoker; /** @@ -253,6 +261,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod */ @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { + Assert.state(this.methodInvoker != null, "No MethodInvoker set"); try { context.setResult(this.methodInvoker.invoke()); } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java index d69f863ed8..362dd3e9c4 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/ResourceLoaderClassLoadHelper.java @@ -44,6 +44,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper { protected static final Log logger = LogFactory.getLog(ResourceLoaderClassLoadHelper.class); + @Nullable private ResourceLoader resourceLoader; @@ -59,7 +60,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper { * Create a new ResourceLoaderClassLoadHelper for the given ResourceLoader. * @param resourceLoader the ResourceLoader to delegate to */ - public ResourceLoaderClassLoadHelper(ResourceLoader resourceLoader) { + public ResourceLoaderClassLoadHelper(@Nullable ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @@ -76,6 +77,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper { @Override public Class loadClass(String name) throws ClassNotFoundException { + Assert.state(this.resourceLoader != null, "ResourceLoaderClassLoadHelper not initialized"); return ClassUtils.forName(name, this.resourceLoader.getClassLoader()); } @@ -87,6 +89,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper { @Override @Nullable public URL getResource(String name) { + Assert.state(this.resourceLoader != null, "ResourceLoaderClassLoadHelper not initialized"); Resource resource = this.resourceLoader.getResource(name); if (resource.exists()) { try { @@ -107,6 +110,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper { @Override @Nullable public InputStream getResourceAsStream(String name) { + Assert.state(this.resourceLoader != null, "ResourceLoaderClassLoadHelper not initialized"); Resource resource = this.resourceLoader.getResource(name); if (resource.exists()) { try { @@ -126,6 +130,7 @@ public class ResourceLoaderClassLoadHelper implements ClassLoadHelper { @Override public ClassLoader getClassLoader() { + Assert.state(this.resourceLoader != null, "ResourceLoaderClassLoadHelper not initialized"); ClassLoader classLoader = this.resourceLoader.getClassLoader(); Assert.state(classLoader != null, "No ClassLoader"); return classLoader; diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java index 69952e6ad0..908b780d70 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.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. @@ -64,22 +64,31 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware { private boolean overwriteExistingJobs = false; + @Nullable private String[] jobSchedulingDataLocations; + @Nullable private List jobDetails; + @Nullable private Map calendars; + @Nullable private List triggers; + @Nullable private SchedulerListener[] schedulerListeners; + @Nullable private JobListener[] globalJobListeners; + @Nullable private TriggerListener[] globalTriggerListeners; + @Nullable private PlatformTransactionManager transactionManager; + @Nullable protected ResourceLoader resourceLoader; @@ -187,7 +196,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware { } @Override - public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { + public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @@ -297,14 +306,15 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware { // Check if the Trigger is aware of an associated JobDetail. JobDetail jobDetail = (JobDetail) trigger.getJobDataMap().remove("jobDetail"); if (triggerExists) { - if (jobDetail != null && !this.jobDetails.contains(jobDetail) && addJobToScheduler(jobDetail)) { + if (jobDetail != null && this.jobDetails != null && + !this.jobDetails.contains(jobDetail) && addJobToScheduler(jobDetail)) { this.jobDetails.add(jobDetail); } getScheduler().rescheduleJob(trigger.getKey(), trigger); } else { try { - if (jobDetail != null && !this.jobDetails.contains(jobDetail) && + if (jobDetail != null && this.jobDetails != null && !this.jobDetails.contains(jobDetail) && (this.overwriteExistingJobs || getScheduler().getJobDetail(jobDetail.getKey()) == null)) { getScheduler().scheduleJob(jobDetail, trigger); this.jobDetails.add(jobDetail); diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessorBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessorBean.java index fdc07d705f..11cd3fe123 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessorBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessorBean.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. @@ -24,6 +24,8 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Spring bean-style class for accessing a Quartz Scheduler, i.e. for registering jobs, @@ -38,10 +40,13 @@ import org.springframework.beans.factory.ListableBeanFactory; */ public class SchedulerAccessorBean extends SchedulerAccessor implements BeanFactoryAware, InitializingBean { + @Nullable private String schedulerName; + @Nullable private Scheduler scheduler; + @Nullable private BeanFactory beanFactory; @@ -74,6 +79,7 @@ public class SchedulerAccessorBean extends SchedulerAccessor implements BeanFact */ @Override public Scheduler getScheduler() { + Assert.state(this.scheduler != null, "No Scheduler set"); return this.scheduler; } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java index c20395cad0..35307d5f72 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java @@ -44,6 +44,7 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.lang.Nullable; import org.springframework.scheduling.SchedulingException; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** @@ -165,26 +166,36 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe private Class schedulerFactoryClass = StdSchedulerFactory.class; + @Nullable private String schedulerName; + @Nullable private Resource configLocation; + @Nullable private Properties quartzProperties; + @Nullable private Executor taskExecutor; + @Nullable private DataSource dataSource; + @Nullable private DataSource nonTransactionalDataSource; + @Nullable private Map schedulerContextMap; + @Nullable private ApplicationContext applicationContext; + @Nullable private String applicationContextSchedulerContextKey; + @Nullable private JobFactory jobFactory; private boolean jobFactorySet = false; @@ -201,6 +212,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe private boolean waitForJobsToCompleteOnShutdown = false; + @Nullable private Scheduler scheduler; @@ -625,7 +637,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe private void populateSchedulerContext() throws SchedulerException { // Put specified objects into Scheduler context. if (this.schedulerContextMap != null) { - this.scheduler.getContext().putAll(this.schedulerContextMap); + getScheduler().getContext().putAll(this.schedulerContextMap); } // Register ApplicationContext in Scheduler context. @@ -635,7 +647,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe "SchedulerFactoryBean needs to be set up in an ApplicationContext " + "to be able to handle an 'applicationContextSchedulerContextKey'"); } - this.scheduler.getContext().put(this.applicationContextSchedulerContextKey, this.applicationContext); + getScheduler().getContext().put(this.applicationContextSchedulerContextKey, this.applicationContext); } } @@ -691,6 +703,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe @Override public Scheduler getScheduler() { + Assert.state(this.scheduler != null, "No Scheduler set"); return this.scheduler; } @@ -768,8 +781,10 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe */ @Override public void destroy() throws SchedulerException { - logger.info("Shutting down Quartz Scheduler"); - this.scheduler.shutdown(this.waitForJobsToCompleteOnShutdown); + if (this.scheduler != null) { + logger.info("Shutting down Quartz Scheduler"); + this.scheduler.shutdown(this.waitForJobsToCompleteOnShutdown); + } } } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SimpleTriggerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SimpleTriggerFactoryBean.java index a2e85455de..c5e6e17e19 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SimpleTriggerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SimpleTriggerFactoryBean.java @@ -29,6 +29,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.Constants; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -59,14 +60,18 @@ public class SimpleTriggerFactoryBean implements FactoryBean, Bea private static final Constants constants = new Constants(SimpleTrigger.class); + @Nullable private String name; + @Nullable private String group; + @Nullable private JobDetail jobDetail; private JobDataMap jobDataMap = new JobDataMap(); + @Nullable private Date startTime; private long startDelay; @@ -79,10 +84,13 @@ public class SimpleTriggerFactoryBean implements FactoryBean, Bea private int misfireInstruction; + @Nullable private String description; + @Nullable private String beanName; + @Nullable private SimpleTrigger simpleTrigger; @@ -226,7 +234,7 @@ public class SimpleTriggerFactoryBean implements FactoryBean, Bea } SimpleTriggerImpl sti = new SimpleTriggerImpl(); - sti.setName(this.name); + sti.setName(this.name != null ? this.name : toString()); sti.setGroup(this.group); if (this.jobDetail != null) { sti.setJobKey(this.jobDetail.getKey()); diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SpringBeanJobFactory.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SpringBeanJobFactory.java index 4c13e1478b..efcc289b20 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SpringBeanJobFactory.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SpringBeanJobFactory.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. @@ -43,8 +43,10 @@ import org.springframework.lang.Nullable; */ public class SpringBeanJobFactory extends AdaptableJobFactory implements SchedulerContextAware { + @Nullable private String[] ignoredUnknownProperties; + @Nullable private SchedulerContext schedulerContext; @@ -56,7 +58,7 @@ public class SpringBeanJobFactory extends AdaptableJobFactory implements Schedul * ignored if there is no corresponding property found on the particular * job class (all other unknown properties will still trigger an exception). */ - public void setIgnoredUnknownProperties(@Nullable String... ignoredUnknownProperties) { + public void setIgnoredUnknownProperties(String... ignoredUnknownProperties) { this.ignoredUnknownProperties = ignoredUnknownProperties; } diff --git a/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerConfigurationFactory.java b/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerConfigurationFactory.java index dde83abf13..37793c9e2f 100644 --- a/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerConfigurationFactory.java +++ b/spring-context-support/src/main/java/org/springframework/ui/freemarker/FreeMarkerConfigurationFactory.java @@ -78,20 +78,27 @@ public class FreeMarkerConfigurationFactory { protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private Resource configLocation; + @Nullable private Properties freemarkerSettings; + @Nullable private Map freemarkerVariables; + @Nullable private String defaultEncoding; private final List templateLoaders = new ArrayList<>(); + @Nullable private List preTemplateLoaders; + @Nullable private List postTemplateLoaders; + @Nullable private String[] templateLoaderPaths; private ResourceLoader resourceLoader = new DefaultResourceLoader(); diff --git a/spring-context/src/main/java/org/springframework/cache/Cache.java b/spring-context/src/main/java/org/springframework/cache/Cache.java index 79cef0d170..a4b97d3e3f 100644 --- a/spring-context/src/main/java/org/springframework/cache/Cache.java +++ b/spring-context/src/main/java/org/springframework/cache/Cache.java @@ -169,6 +169,7 @@ public interface Cache { @SuppressWarnings("serial") class ValueRetrievalException extends RuntimeException { + @Nullable private final Object key; public ValueRetrievalException(@Nullable Object key, Callable loader, Throwable ex) { diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java b/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java index 2b08763941..d4c42d5647 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportAware; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; /** @@ -41,14 +42,19 @@ import org.springframework.util.CollectionUtils; @Configuration public abstract class AbstractCachingConfiguration implements ImportAware { + @Nullable protected AnnotationAttributes enableCaching; + @Nullable protected CacheManager cacheManager; + @Nullable protected CacheResolver cacheResolver; + @Nullable protected KeyGenerator keyGenerator; + @Nullable protected CacheErrorHandler errorHandler; diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.java b/spring-context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.java index e6b2d48f5d..ecee988749 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.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. @@ -44,7 +44,9 @@ public class ProxyCachingConfiguration extends AbstractCachingConfiguration { new BeanFactoryCacheOperationSourceAdvisor(); advisor.setCacheOperationSource(cacheOperationSource()); advisor.setAdvice(cacheInterceptor()); - advisor.setOrder(this.enableCaching.getNumber("order")); + if (this.enableCaching != null) { + advisor.setOrder(this.enableCaching.getNumber("order")); + } return advisor; } diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java b/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java index 658686dc6c..3134029bd6 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java @@ -263,12 +263,16 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria */ static class DefaultCacheConfig { + @Nullable private final String[] cacheNames; + @Nullable private final String keyGenerator; + @Nullable private final String cacheManager; + @Nullable private final String cacheResolver; public DefaultCacheConfig() { diff --git a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java index b7539f93fe..361ed2b662 100644 --- a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java +++ b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java @@ -52,6 +52,7 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { private final ConcurrentMap store; + @Nullable private final SerializationDelegate serialization; @@ -176,7 +177,7 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { Object storeValue = super.toStoreValue(userValue); if (this.serialization != null) { try { - return serializeValue(storeValue); + return serializeValue(this.serialization, storeValue); } catch (Throwable ex) { throw new IllegalArgumentException("Failed to serialize cache value '" + userValue + @@ -188,10 +189,10 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { } } - private Object serializeValue(Object storeValue) throws IOException { + private Object serializeValue(SerializationDelegate serialization, Object storeValue) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { - this.serialization.serialize(storeValue, out); + serialization.serialize(storeValue, out); return out.toByteArray(); } finally { @@ -203,7 +204,7 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { protected Object fromStoreValue(Object storeValue) { if (this.serialization != null) { try { - return super.fromStoreValue(deserializeValue(storeValue)); + return super.fromStoreValue(deserializeValue(this.serialization, storeValue)); } catch (Throwable ex) { throw new IllegalArgumentException("Failed to deserialize cache value '" + storeValue + "'", ex); @@ -215,10 +216,10 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { } - private Object deserializeValue(Object storeValue) throws IOException { + private Object deserializeValue(SerializationDelegate serialization, Object storeValue) throws IOException { ByteArrayInputStream in = new ByteArrayInputStream((byte[]) storeValue); try { - return this.serialization.deserialize(in); + return serialization.deserialize(in); } finally { in.close(); diff --git a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.java b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.java index 0e0b5a8adf..1ec7322b66 100644 --- a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.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.util.concurrent.ConcurrentMap; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -41,10 +42,12 @@ public class ConcurrentMapCacheFactoryBean private String name = ""; + @Nullable private ConcurrentMap store; private boolean allowNullValues = true; + @Nullable private ConcurrentMapCache cache; diff --git a/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java b/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java index 8503fcc690..b879c823e9 100644 --- a/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java +++ b/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.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. @@ -197,7 +197,8 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { private String method; - private String[] caches = null; + @Nullable + private String[] caches; Props(Element root) { String defaultCache = root.getAttribute("cache"); @@ -220,12 +221,12 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { if (StringUtils.hasText(cache)) { localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim()); } - else { - if (this.caches == null) { - readerCtx.error("No cache specified for " + element.getNodeName(), element); - } + if (localCaches != null) { + builder.setCacheNames(localCaches); + } + else { + readerCtx.error("No cache specified for " + element.getNodeName(), element); } - builder.setCacheNames(localCaches); builder.setKey(getAttributeValue(element, "key", this.key)); builder.setKeyGenerator(getAttributeValue(element, "key-generator", this.keyGenerator)); @@ -233,8 +234,8 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { builder.setCondition(getAttributeValue(element, "condition", this.condition)); if (StringUtils.hasText(builder.getKey()) && StringUtils.hasText(builder.getKeyGenerator())) { - throw new IllegalStateException("Invalid cache advice configuration on '" - + element.toString() + "'. Both 'key' and 'keyGenerator' attributes have been set. " + + throw new IllegalStateException("Invalid cache advice configuration on '" + + element.toString() + "'. Both 'key' and 'keyGenerator' attributes have been set. " + "These attributes are mutually exclusive: either set the SpEL expression used to" + "compute the key at runtime or set the name of the KeyGenerator bean to use."); } diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java index e7704cd359..d8138c6256 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2012 the original author or authors. + * Copyright 2010-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import org.springframework.aop.support.DefaultPointcutAdvisor; * of the Spring reference documentation for more information. * * @author Costin Leau + * @author Juergen Hoeller * @since 3.1 * @see org.springframework.aop.framework.ProxyFactoryBean * @see CacheInterceptor @@ -44,9 +45,16 @@ public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean { private final CacheInterceptor cachingInterceptor = new CacheInterceptor(); - private Pointcut pointcut; + private Pointcut pointcut = Pointcut.TRUE; + /** + * Set the sources used to find cache operations. + */ + public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) { + this.cachingInterceptor.setCacheOperationSources(cacheOperationSources); + } + /** * Set a pointcut, i.e a bean that can cause conditional invocation * of the CacheInterceptor depending on method and attributes passed. @@ -58,21 +66,11 @@ public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean { this.pointcut = pointcut; } + @Override protected Object createMainInterceptor() { this.cachingInterceptor.afterPropertiesSet(); - if (this.pointcut == null) { - // Rely on default pointcut. - throw new UnsupportedOperationException(); - } return new DefaultPointcutAdvisor(this.pointcut, this.cachingInterceptor); } - /** - * Set the sources used to find cache operations. - */ - public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) { - this.cachingInterceptor.setCacheOperationSources(cacheOperationSources); - } - } diff --git a/spring-context/src/main/java/org/springframework/cache/support/SimpleValueWrapper.java b/spring-context/src/main/java/org/springframework/cache/support/SimpleValueWrapper.java index 3c94d081a3..4524dd3935 100644 --- a/spring-context/src/main/java/org/springframework/cache/support/SimpleValueWrapper.java +++ b/spring-context/src/main/java/org/springframework/cache/support/SimpleValueWrapper.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. @@ -28,6 +28,7 @@ import org.springframework.lang.Nullable; */ public class SimpleValueWrapper implements ValueWrapper { + @Nullable private final Object value; diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java index b6ce1f8f5d..aefd00d5be 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.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. @@ -66,6 +66,7 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults(); + @Nullable private String[] autowireCandidatePatterns; private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java index cc7603e11e..6a5f31df6f 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java @@ -42,6 +42,7 @@ import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.core.type.AnnotationMetadata; @@ -97,14 +98,19 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC private final List excludeFilters = new LinkedList<>(); + @Nullable private Environment environment; + @Nullable private ConditionEvaluator conditionEvaluator; + @Nullable private ResourcePatternResolver resourcePatternResolver; + @Nullable private MetadataReaderFactory metadataReaderFactory; + @Nullable private CandidateComponentsIndex componentsIndex; @@ -232,6 +238,9 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC @Override public final Environment getEnvironment() { + if (this.environment == null) { + this.environment = new StandardEnvironment(); + } return this.environment; } @@ -262,6 +271,13 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * Return the ResourceLoader that this component provider uses. */ public final ResourceLoader getResourceLoader() { + return getResourcePatternResolver(); + } + + private ResourcePatternResolver getResourcePatternResolver() { + if (this.resourcePatternResolver == null) { + this.resourcePatternResolver = new PathMatchingResourcePatternResolver(); + } return this.resourcePatternResolver; } @@ -280,6 +296,9 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * Return the MetadataReaderFactory used by this component provider. */ public final MetadataReaderFactory getMetadataReaderFactory() { + if (this.metadataReaderFactory == null) { + this.metadataReaderFactory = new CachingMetadataReaderFactory(); + } return this.metadataReaderFactory; } @@ -290,8 +309,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * @return a corresponding Set of autodetected bean definitions */ public Set findCandidateComponents(String basePackage) { - if (isIndexSupported()) { - return addCandidateComponentsFromIndex(basePackage); + if (this.componentsIndex != null && indexSupportsIncludeFilters()) { + return addCandidateComponentsFromIndex(this.componentsIndex, basePackage); } else { return scanCandidateComponents(basePackage); @@ -304,12 +323,9 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * instance is supported by it, {@code false} otherwise * @since 5.0 */ - protected boolean isIndexSupported() { - if (this.componentsIndex == null) { - return false; - } + private boolean indexSupportsIncludeFilters() { for (TypeFilter includeFilter : this.includeFilters) { - if (!isIndexSupportsIncludeFilter(includeFilter)) { + if (!indexSupportsIncludeFilter(includeFilter)) { return false; } } @@ -323,7 +339,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * @since 5.0 * @see #extractStereotype(TypeFilter) */ - protected boolean isIndexSupportsIncludeFilter(TypeFilter filter) { + private boolean indexSupportsIncludeFilter(TypeFilter filter) { if (filter instanceof AnnotationTypeFilter) { Class annotation = ((AnnotationTypeFilter) filter).getAnnotationType(); return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) || @@ -341,10 +357,10 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * @param filter the filter to handle * @return the stereotype in the index matching this filter * @since 5.0 - * @see #isIndexSupportsIncludeFilter(TypeFilter) + * @see #indexSupportsIncludeFilter(TypeFilter) */ @Nullable - protected String extractStereotype(TypeFilter filter) { + private String extractStereotype(TypeFilter filter) { if (filter instanceof AnnotationTypeFilter) { return ((AnnotationTypeFilter) filter).getAnnotationType().getName(); } @@ -354,7 +370,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC return null; } - private Set addCandidateComponentsFromIndex(String basePackage) { + private Set addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) { Set candidates = new LinkedHashSet<>(); try { Set types = new HashSet<>(); @@ -363,12 +379,12 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC if (stereotype == null) { throw new IllegalArgumentException("Failed to extract stereotype from "+ filter); } - types.addAll(this.componentsIndex.getCandidateTypes(basePackage, stereotype)); + types.addAll(index.getCandidateTypes(basePackage, stereotype)); } boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); for (String type : types) { - MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type); + MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type); if (isCandidateComponent(metadataReader)) { AnnotatedGenericBeanDefinition sbd = new AnnotatedGenericBeanDefinition( metadataReader.getAnnotationMetadata()); @@ -402,7 +418,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; - Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); + Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); for (Resource resource : resources) { @@ -411,7 +427,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC } if (resource.isReadable()) { try { - MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); + MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); @@ -462,7 +478,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * @return the pattern specification to be used for package searching */ protected String resolveBasePackage(String basePackage) { - return ClassUtils.convertClassNameToResourcePath(this.environment.resolveRequiredPlaceholders(basePackage)); + return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage)); } /** @@ -473,12 +489,12 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC */ protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { - if (tf.match(metadataReader, this.metadataReaderFactory)) { + if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } for (TypeFilter tf : this.includeFilters) { - if (tf.match(metadataReader, this.metadataReaderFactory)) { + if (tf.match(metadataReader, getMetadataReaderFactory())) { return isConditionMatch(metadataReader); } } @@ -493,7 +509,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC */ private boolean isConditionMatch(MetadataReader metadataReader) { if (this.conditionEvaluator == null) { - this.conditionEvaluator = new ConditionEvaluator(getRegistry(), getEnvironment(), getResourceLoader()); + this.conditionEvaluator = + new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver); } return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata()); } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java index 2efcefaf80..640f869b8c 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java @@ -143,12 +143,11 @@ import org.springframework.util.StringValueResolver; public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable { - // Common Annotations 1.1 Resource.lookup() available? Not present on JDK 6... - private static final Method lookupAttribute = ClassUtils.getMethodIfAvailable(Resource.class, "lookup"); + @Nullable + private static Class webServiceRefClass; - private static Class webServiceRefClass = null; - - private static Class ejbRefClass = null; + @Nullable + private static Class ejbRefClass; static { try { @@ -180,14 +179,16 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean private transient BeanFactory jndiFactory = new SimpleJndiBeanFactory(); + @Nullable private transient BeanFactory resourceFactory; + @Nullable private transient BeanFactory beanFactory; + @Nullable private transient StringValueResolver embeddedValueResolver; - private transient final Map injectionMetadataCache = - new ConcurrentHashMap<>(256); + private transient final Map injectionMetadataCache = new ConcurrentHashMap<>(256); /** @@ -532,12 +533,13 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean */ protected abstract class LookupElement extends InjectionMetadata.InjectedElement { - protected String name; + protected String name = ""; protected boolean isDefaultName = false; - protected Class lookupType; + protected Class lookupType = Object.class; + @Nullable protected String mappedName; public LookupElement(Member member, @Nullable PropertyDescriptor pd) { @@ -602,10 +604,9 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean // No resource type specified... check field/method. resourceType = getResourceType(); } - this.name = resourceName; + this.name = (resourceName != null ? resourceName : ""); this.lookupType = resourceType; - String lookupValue = (lookupAttribute != null ? - (String) ReflectionUtils.invokeMethod(lookupAttribute, resource) : null); + String lookupValue = resource.lookup(); this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName()); Lazy lazy = ae.getAnnotation(Lazy.class); this.lazyLookup = (lazy != null && lazy.value()); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConditionEvaluator.java b/spring-context/src/main/java/org/springframework/context/annotation/ConditionEvaluator.java index 1f1eeea21c..ea9bdba8bb 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConditionEvaluator.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConditionEvaluator.java @@ -133,14 +133,17 @@ class ConditionEvaluator { */ private static class ConditionContextImpl implements ConditionContext { + @Nullable private final BeanDefinitionRegistry registry; + @Nullable private final ConfigurableListableBeanFactory beanFactory; private final Environment environment; private final ResourceLoader resourceLoader; + @Nullable private final ClassLoader classLoader; public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry, diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java index 435d76febb..d35ecd062b 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java @@ -95,7 +95,7 @@ class ConfigurationClassEnhancer { * container-aware callbacks capable of respecting scoping and other bean semantics. * @return the enhanced subclass */ - public Class enhance(Class configClass, ClassLoader classLoader) { + public Class enhance(Class configClass, @Nullable ClassLoader classLoader) { if (EnhancedConfiguration.class.isAssignableFrom(configClass)) { if (logger.isDebugEnabled()) { logger.debug(String.format("Ignoring request to enhance %s as it has " + @@ -118,7 +118,7 @@ class ConfigurationClassEnhancer { /** * Creates a new CGLIB {@link Enhancer} instance. */ - private Enhancer newEnhancer(Class superclass, ClassLoader classLoader) { + private Enhancer newEnhancer(Class superclass, @Nullable ClassLoader classLoader) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(superclass); enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class}); @@ -210,6 +210,7 @@ class ConfigurationClassEnhancer { */ private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy { + @Nullable private final ClassLoader classLoader; public BeanFactoryAwareGeneratorStrategy(@Nullable ClassLoader classLoader) { diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index 88dcbcb4ac..a8ed2ad816 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -133,6 +133,7 @@ class ConfigurationClassParser { private final ImportStack importStack = new ImportStack(); + @Nullable private List deferredImportSelectors; @@ -539,8 +540,11 @@ class ConfigurationClassParser { private void processDeferredImportSelectors() { List deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; - Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); + if (deferredImports == null) { + return; + } + Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 7093daad98..6969ee0231 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -54,6 +54,7 @@ import org.springframework.context.annotation.ConfigurationClassEnhancer.Enhance import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; import org.springframework.core.env.Environment; +import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.AnnotationMetadata; @@ -96,10 +97,12 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo private ProblemReporter problemReporter = new FailFastProblemReporter(); + @Nullable private Environment environment; private ResourceLoader resourceLoader = new DefaultResourceLoader(); + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(); @@ -110,6 +113,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo private final Set factoriesPostProcessed = new HashSet<>(); + @Nullable private ConfigurationClassBeanDefinitionReader reader; private boolean localBeanNameGeneratorSet = false; @@ -193,7 +197,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo } @Override - public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { + public void setResourceLoader(ResourceLoader resourceLoader) { Assert.notNull(resourceLoader, "ResourceLoader must not be null"); this.resourceLoader = resourceLoader; if (!this.setMetadataReaderFactoryCalled) { @@ -297,6 +301,10 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo } } + if (this.environment == null) { + this.environment = new StandardEnvironment(); + } + // Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, diff --git a/spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfiguration.java b/spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfiguration.java index a7e3de0f10..9fad583329 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfiguration.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * {@code @Configuration} class that registers a {@link LoadTimeWeaver} bean. @@ -43,10 +44,13 @@ import org.springframework.lang.Nullable; @Configuration public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoaderAware { + @Nullable private AnnotationAttributes enableLTW; + @Nullable private LoadTimeWeavingConfigurer ltwConfigurer; + @Nullable private ClassLoader beanClassLoader; @@ -65,7 +69,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade } @Override - public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) { + public void setBeanClassLoader(ClassLoader beanClassLoader) { this.beanClassLoader = beanClassLoader; } @@ -73,6 +77,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade @Bean(name = ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public LoadTimeWeaver loadTimeWeaver() { + Assert.state(this.beanClassLoader != null, "No ClassLoader set"); LoadTimeWeaver loadTimeWeaver = null; if (this.ltwConfigurer != null) { @@ -85,22 +90,24 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade loadTimeWeaver = new DefaultContextLoadTimeWeaver(this.beanClassLoader); } - AspectJWeaving aspectJWeaving = this.enableLTW.getEnum("aspectjWeaving"); - switch (aspectJWeaving) { - case DISABLED: - // AJ weaving is disabled -> do nothing - break; - case AUTODETECT: - if (this.beanClassLoader.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) == null) { - // No aop.xml present on the classpath -> treat as 'disabled' + if (this.enableLTW != null) { + AspectJWeaving aspectJWeaving = this.enableLTW.getEnum("aspectjWeaving"); + switch (aspectJWeaving) { + case DISABLED: + // AJ weaving is disabled -> do nothing break; - } - // aop.xml is present on the classpath -> enable - AspectJWeavingEnabler.enableAspectJWeaving(loadTimeWeaver, this.beanClassLoader); - break; - case ENABLED: - AspectJWeavingEnabler.enableAspectJWeaving(loadTimeWeaver, this.beanClassLoader); - break; + case AUTODETECT: + if (this.beanClassLoader.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) == null) { + // No aop.xml present on the classpath -> treat as 'disabled' + break; + } + // aop.xml is present on the classpath -> enable + AspectJWeavingEnabler.enableAspectJWeaving(loadTimeWeaver, this.beanClassLoader); + break; + case ENABLED: + AspectJWeavingEnabler.enableAspectJWeaving(loadTimeWeaver, this.beanClassLoader); + break; + } } return loadTimeWeaver; diff --git a/spring-context/src/main/java/org/springframework/context/annotation/MBeanExportConfiguration.java b/spring-context/src/main/java/org/springframework/context/annotation/MBeanExportConfiguration.java index 059eea0ccc..759bd8d14e 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/MBeanExportConfiguration.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/MBeanExportConfiguration.java @@ -33,6 +33,7 @@ import org.springframework.jmx.support.RegistrationPolicy; import org.springframework.jmx.support.WebSphereMBeanServerFactoryBean; import org.springframework.jndi.JndiLocatorDelegate; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -52,10 +53,13 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware, private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter"; + @Nullable private AnnotationAttributes enableMBeanExport; + @Nullable private Environment environment; + @Nullable private BeanFactory beanFactory; @@ -84,14 +88,15 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware, @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public AnnotationMBeanExporter mbeanExporter() { AnnotationMBeanExporter exporter = new AnnotationMBeanExporter(); - setupDomain(exporter); - setupServer(exporter); - setupRegistrationPolicy(exporter); + Assert.state(this.enableMBeanExport != null, "No EnableMBeanExport annotation found"); + setupDomain(exporter, this.enableMBeanExport); + setupServer(exporter, this.enableMBeanExport); + setupRegistrationPolicy(exporter, this.enableMBeanExport); return exporter; } - private void setupDomain(AnnotationMBeanExporter exporter) { - String defaultDomain = this.enableMBeanExport.getString("defaultDomain"); + private void setupDomain(AnnotationMBeanExporter exporter, AnnotationAttributes enableMBeanExport) { + String defaultDomain = enableMBeanExport.getString("defaultDomain"); if (StringUtils.hasLength(defaultDomain) && this.environment != null) { defaultDomain = this.environment.resolvePlaceholders(defaultDomain); } @@ -100,12 +105,13 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware, } } - private void setupServer(AnnotationMBeanExporter exporter) { - String server = this.enableMBeanExport.getString("server"); + private void setupServer(AnnotationMBeanExporter exporter, AnnotationAttributes enableMBeanExport) { + String server = enableMBeanExport.getString("server"); if (StringUtils.hasLength(server) && this.environment != null) { server = this.environment.resolvePlaceholders(server); } if (StringUtils.hasText(server)) { + Assert.state(this.beanFactory != null, "No BeanFactory set"); exporter.setServer(this.beanFactory.getBean(server, MBeanServer.class)); } else { @@ -119,8 +125,8 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware, } } - private void setupRegistrationPolicy(AnnotationMBeanExporter exporter) { - RegistrationPolicy registrationPolicy = this.enableMBeanExport.getEnum("registration"); + private void setupRegistrationPolicy(AnnotationMBeanExporter exporter, AnnotationAttributes enableMBeanExport) { + RegistrationPolicy registrationPolicy = enableMBeanExport.getEnum("registration"); exporter.setRegistrationPolicy(registrationPolicy); } diff --git a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java index b8e53c7443..477d1a86a1 100644 --- a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java +++ b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java @@ -65,8 +65,10 @@ public abstract class AbstractApplicationEventMulticaster final Map retrieverCache = new ConcurrentHashMap<>(64); + @Nullable private ClassLoader beanClassLoader; + @Nullable private BeanFactory beanFactory; private Object retrievalMutex = this.defaultRetriever; @@ -300,6 +302,7 @@ public abstract class AbstractApplicationEventMulticaster private final ResolvableType eventType; + @Nullable private final Class sourceType; public ListenerCacheKey(ResolvableType eventType, @Nullable Class sourceType) { diff --git a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java index 5924c23d76..0ed2d4ffe5 100644 --- a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java +++ b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java @@ -71,14 +71,17 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe private final List declaredEventTypes; + @Nullable private final String condition; private final int order; private final AnnotatedElementKey methodKey; + @Nullable private ApplicationContext applicationContext; + @Nullable private EventExpressionEvaluator evaluator; @@ -291,6 +294,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe * annotation or any matching attribute on a composed annotation that * is meta-annotated with {@code @EventListener}. */ + @Nullable protected String getCondition() { return this.condition; } diff --git a/spring-context/src/main/java/org/springframework/context/event/EventPublicationInterceptor.java b/spring-context/src/main/java/org/springframework/context/event/EventPublicationInterceptor.java index 259dc150b1..8591e19f77 100644 --- a/spring-context/src/main/java/org/springframework/context/event/EventPublicationInterceptor.java +++ b/spring-context/src/main/java/org/springframework/context/event/EventPublicationInterceptor.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. @@ -25,6 +25,8 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * {@link MethodInterceptor Interceptor} that publishes an @@ -48,8 +50,10 @@ import org.springframework.context.ApplicationEventPublisherAware; public class EventPublicationInterceptor implements MethodInterceptor, ApplicationEventPublisherAware, InitializingBean { + @Nullable private Constructor applicationEventClassConstructor; + @Nullable private ApplicationEventPublisher applicationEventPublisher; @@ -64,15 +68,14 @@ public class EventPublicationInterceptor */ public void setApplicationEventClass(Class applicationEventClass) { if (ApplicationEvent.class == applicationEventClass || - !ApplicationEvent.class.isAssignableFrom(applicationEventClass)) { - throw new IllegalArgumentException("applicationEventClass needs to extend ApplicationEvent"); + !ApplicationEvent.class.isAssignableFrom(applicationEventClass)) { + throw new IllegalArgumentException("'applicationEventClass' needs to extend ApplicationEvent"); } try { - this.applicationEventClassConstructor = - applicationEventClass.getConstructor(new Class[] {Object.class}); + this.applicationEventClassConstructor = applicationEventClass.getConstructor(Object.class); } catch (NoSuchMethodException ex) { - throw new IllegalArgumentException("applicationEventClass [" + + throw new IllegalArgumentException("ApplicationEvent class [" + applicationEventClass.getName() + "] does not have the required Object constructor: " + ex); } } @@ -85,7 +88,7 @@ public class EventPublicationInterceptor @Override public void afterPropertiesSet() throws Exception { if (this.applicationEventClassConstructor == null) { - throw new IllegalArgumentException("applicationEventClass is required"); + throw new IllegalArgumentException("Property 'applicationEventClass' is required"); } } @@ -94,8 +97,11 @@ public class EventPublicationInterceptor public Object invoke(MethodInvocation invocation) throws Throwable { Object retVal = invocation.proceed(); + Assert.state(this.applicationEventClassConstructor != null, "No ApplicationEvent class set"); ApplicationEvent event = (ApplicationEvent) - this.applicationEventClassConstructor.newInstance(new Object[] {invocation.getThis()}); + this.applicationEventClassConstructor.newInstance(invocation.getThis()); + + Assert.state(this.applicationEventPublisher != null, "No ApplicationEventPublisher available"); this.applicationEventPublisher.publishEvent(event); return retVal; diff --git a/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java b/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java index ff160403a0..127d24250f 100644 --- a/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java +++ b/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java @@ -37,6 +37,7 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList private final ApplicationListener delegate; + @Nullable private final ResolvableType declaredEventType; diff --git a/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java b/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java index b7bfe0f02a..468545eb7b 100644 --- a/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java +++ b/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java @@ -48,8 +48,10 @@ import org.springframework.util.ErrorHandler; */ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { + @Nullable private Executor taskExecutor; + @Nullable private ErrorHandler errorHandler; diff --git a/spring-context/src/main/java/org/springframework/context/event/SourceFilteringListener.java b/spring-context/src/main/java/org/springframework/context/event/SourceFilteringListener.java index 8337c02786..e397db9b2a 100644 --- a/spring-context/src/main/java/org/springframework/context/event/SourceFilteringListener.java +++ b/spring-context/src/main/java/org/springframework/context/event/SourceFilteringListener.java @@ -38,6 +38,7 @@ public class SourceFilteringListener implements GenericApplicationListener, Smar private final Object source; + @Nullable private GenericApplicationListener delegate; diff --git a/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.java b/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.java index 50812c11c0..26b300eb84 100644 --- a/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.java +++ b/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.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.context.expression; import java.lang.reflect.AnnotatedElement; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -34,6 +35,7 @@ public final class AnnotatedElementKey implements Comparable targetClass; @@ -41,7 +43,7 @@ public final class AnnotatedElementKey implements Comparable targetClass) { + public AnnotatedElementKey(AnnotatedElement element, @Nullable Class targetClass) { Assert.notNull(element, "AnnotatedElement must not be null"); this.element = element; this.targetClass = targetClass; @@ -75,6 +77,9 @@ public final class AnnotatedElementKey implements Comparable("LocaleContext"); // Shared default locale at the framework level + @Nullable private static Locale defaultLocale; // Shared default time zone at the framework level + @Nullable private static TimeZone defaultTimeZone; diff --git a/spring-context/src/main/java/org/springframework/context/i18n/SimpleLocaleContext.java b/spring-context/src/main/java/org/springframework/context/i18n/SimpleLocaleContext.java index 7c6dc9924e..ab0f85f108 100644 --- a/spring-context/src/main/java/org/springframework/context/i18n/SimpleLocaleContext.java +++ b/spring-context/src/main/java/org/springframework/context/i18n/SimpleLocaleContext.java @@ -32,6 +32,7 @@ import org.springframework.lang.Nullable; */ public class SimpleLocaleContext implements LocaleContext { + @Nullable private final Locale locale; @@ -45,6 +46,7 @@ public class SimpleLocaleContext implements LocaleContext { } @Override + @Nullable public Locale getLocale() { return this.locale; } diff --git a/spring-context/src/main/java/org/springframework/context/i18n/SimpleTimeZoneAwareLocaleContext.java b/spring-context/src/main/java/org/springframework/context/i18n/SimpleTimeZoneAwareLocaleContext.java index 0c1cf6cf49..5a117cdcf2 100644 --- a/spring-context/src/main/java/org/springframework/context/i18n/SimpleTimeZoneAwareLocaleContext.java +++ b/spring-context/src/main/java/org/springframework/context/i18n/SimpleTimeZoneAwareLocaleContext.java @@ -36,6 +36,7 @@ import org.springframework.lang.Nullable; */ public class SimpleTimeZoneAwareLocaleContext extends SimpleLocaleContext implements TimeZoneAwareLocaleContext { + @Nullable private final TimeZone timeZone; @@ -53,6 +54,7 @@ public class SimpleTimeZoneAwareLocaleContext extends SimpleLocaleContext implem @Override + @Nullable public TimeZone getTimeZone() { return this.timeZone; } diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index 01d16fcb60..5f448c63ea 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -167,9 +167,11 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader private String displayName = ObjectUtils.identityToString(this); /** Parent context */ + @Nullable private ApplicationContext parent; /** Environment used by this context */ + @Nullable private ConfigurableEnvironment environment; /** BeanFactoryPostProcessors to apply on refresh */ @@ -188,24 +190,29 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader private final Object startupShutdownMonitor = new Object(); /** Reference to the JVM shutdown hook, if registered */ + @Nullable private Thread shutdownHook; /** ResourcePatternResolver used by this context */ private ResourcePatternResolver resourcePatternResolver; /** LifecycleProcessor for managing the lifecycle of beans within this context */ + @Nullable private LifecycleProcessor lifecycleProcessor; /** MessageSource we delegate our implementation of this interface to */ + @Nullable private MessageSource messageSource; /** Helper class used in event publishing */ + @Nullable private ApplicationEventMulticaster applicationEventMulticaster; /** Statically specified listeners */ private final Set> applicationListeners = new LinkedHashSet<>(); /** ApplicationEvents published early */ + @Nullable private Set earlyApplicationEvents; @@ -275,6 +282,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader * (that is, this context is the root of the context hierarchy). */ @Override + @Nullable public ApplicationContext getParent() { return this.parent; } diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/AbstractMessageSource.java index b06f21e260..55811ec0fa 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractMessageSource.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractMessageSource.java @@ -64,8 +64,10 @@ import org.springframework.util.ObjectUtils; */ public abstract class AbstractMessageSource extends MessageSourceSupport implements HierarchicalMessageSource { + @Nullable private MessageSource parentMessageSource; + @Nullable private Properties commonMessages; private boolean useCodeAsDefaultMessage = false; @@ -77,6 +79,7 @@ public abstract class AbstractMessageSource extends MessageSourceSupport impleme } @Override + @Nullable public MessageSource getParentMessageSource() { return this.parentMessageSource; } diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java index 7fdbf5a02f..463fb99556 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java @@ -64,11 +64,14 @@ import org.springframework.lang.Nullable; */ public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { + @Nullable private Boolean allowBeanDefinitionOverriding; + @Nullable private Boolean allowCircularReferences; /** Bean factory for this context */ + @Nullable private DefaultListableBeanFactory beanFactory; /** Synchronization monitor for the internal BeanFactory */ @@ -149,8 +152,10 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl @Override protected final void closeBeanFactory() { synchronized (this.beanFactoryMonitor) { - this.beanFactory.setSerializationId(null); - this.beanFactory = null; + if (this.beanFactory != null) { + this.beanFactory.setSerializationId(null); + this.beanFactory = null; + } } } diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java index 2c3172da56..5e142b4aaf 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java @@ -39,6 +39,7 @@ import org.springframework.util.StringUtils; public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext implements BeanNameAware, InitializingBean { + @Nullable private String[] configLocations; private boolean setIdCalled = false; diff --git a/spring-context/src/main/java/org/springframework/context/support/ApplicationListenerDetector.java b/spring-context/src/main/java/org/springframework/context/support/ApplicationListenerDetector.java index 00947d7985..66970bdaa8 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ApplicationListenerDetector.java +++ b/spring-context/src/main/java/org/springframework/context/support/ApplicationListenerDetector.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. @@ -27,6 +27,7 @@ import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcess import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ApplicationEventMulticaster; +import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -46,6 +47,7 @@ class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, private static final Log logger = LogFactory.getLog(ApplicationListenerDetector.class); + @Nullable private transient final AbstractApplicationContext applicationContext; private transient final Map singletonNames = new ConcurrentHashMap<>(256); diff --git a/spring-context/src/main/java/org/springframework/context/support/ApplicationObjectSupport.java b/spring-context/src/main/java/org/springframework/context/support/ApplicationObjectSupport.java index d45602148a..c9c90f63da 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ApplicationObjectSupport.java +++ b/spring-context/src/main/java/org/springframework/context/support/ApplicationObjectSupport.java @@ -52,9 +52,11 @@ public abstract class ApplicationObjectSupport implements ApplicationContextAwar protected final Log logger = LogFactory.getLog(getClass()); /** ApplicationContext this object runs in */ + @Nullable private ApplicationContext applicationContext; /** MessageSourceAccessor for easy message access */ + @Nullable private MessageSourceAccessor messageSourceAccessor; diff --git a/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java b/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java index 75d4d52768..45c4eb3362 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java +++ b/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java @@ -23,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.core.DecoratingClassLoader; import org.springframework.core.OverridingClassLoader; import org.springframework.core.SmartClassLoader; +import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; /** @@ -59,7 +60,7 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart private final Map bytesCache = new ConcurrentHashMap<>(256); - public ContextTypeMatchClassLoader(ClassLoader parent) { + public ContextTypeMatchClassLoader(@Nullable ClassLoader parent) { super(parent); } diff --git a/spring-context/src/main/java/org/springframework/context/support/DefaultMessageSourceResolvable.java b/spring-context/src/main/java/org/springframework/context/support/DefaultMessageSourceResolvable.java index 90cf1fec0b..8c2b94f48a 100644 --- a/spring-context/src/main/java/org/springframework/context/support/DefaultMessageSourceResolvable.java +++ b/spring-context/src/main/java/org/springframework/context/support/DefaultMessageSourceResolvable.java @@ -35,10 +35,13 @@ import org.springframework.util.StringUtils; @SuppressWarnings("serial") public class DefaultMessageSourceResolvable implements MessageSourceResolvable, Serializable { + @Nullable private final String[] codes; + @Nullable private final Object[] arguments; + @Nullable private final String defaultMessage; @@ -109,16 +112,19 @@ public class DefaultMessageSourceResolvable implements MessageSourceResolvable, } @Override + @Nullable public String[] getCodes() { return this.codes; } @Override + @Nullable public Object[] getArguments() { return this.arguments; } @Override + @Nullable public String getDefaultMessage() { return this.defaultMessage; } diff --git a/spring-context/src/main/java/org/springframework/context/support/DelegatingMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/DelegatingMessageSource.java index 136508e5c4..cbd370a1d0 100644 --- a/spring-context/src/main/java/org/springframework/context/support/DelegatingMessageSource.java +++ b/spring-context/src/main/java/org/springframework/context/support/DelegatingMessageSource.java @@ -37,6 +37,7 @@ import org.springframework.lang.Nullable; */ public class DelegatingMessageSource extends MessageSourceSupport implements HierarchicalMessageSource { + @Nullable private MessageSource parentMessageSource; @@ -46,6 +47,7 @@ public class DelegatingMessageSource extends MessageSourceSupport implements Hie } @Override + @Nullable public MessageSource getParentMessageSource() { return this.parentMessageSource; } diff --git a/spring-context/src/main/java/org/springframework/context/support/EmbeddedValueResolutionSupport.java b/spring-context/src/main/java/org/springframework/context/support/EmbeddedValueResolutionSupport.java index cf627c96d1..bea6c02269 100644 --- a/spring-context/src/main/java/org/springframework/context/support/EmbeddedValueResolutionSupport.java +++ b/spring-context/src/main/java/org/springframework/context/support/EmbeddedValueResolutionSupport.java @@ -29,6 +29,7 @@ import org.springframework.util.StringValueResolver; */ public class EmbeddedValueResolutionSupport implements EmbeddedValueResolverAware { + @Nullable private StringValueResolver embeddedValueResolver; diff --git a/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java index 22172a7c15..f094c231b5 100644 --- a/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java @@ -93,6 +93,7 @@ public class GenericApplicationContext extends AbstractApplicationContext implem private final DefaultListableBeanFactory beanFactory; + @Nullable private ResourceLoader resourceLoader; private boolean customClassLoader = false; diff --git a/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java b/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java index ea738456f0..6a7085eccc 100644 --- a/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java +++ b/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java @@ -56,9 +56,9 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar public static final String MBEAN_APPLICATION_KEY = "application"; - private static final Set applicationContexts = - new LinkedHashSet<>(); + private static final Set applicationContexts = new LinkedHashSet<>(); + @Nullable private static String applicationName; @@ -103,6 +103,7 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar } + @Nullable private ConfigurableApplicationContext applicationContext; diff --git a/spring-context/src/main/java/org/springframework/context/support/MessageSourceAccessor.java b/spring-context/src/main/java/org/springframework/context/support/MessageSourceAccessor.java index 808766d297..90a584e25a 100644 --- a/spring-context/src/main/java/org/springframework/context/support/MessageSourceAccessor.java +++ b/spring-context/src/main/java/org/springframework/context/support/MessageSourceAccessor.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. @@ -39,8 +39,10 @@ public class MessageSourceAccessor { private final MessageSource messageSource; + @Nullable private final Locale defaultLocale; + /** * Create a new MessageSourceAccessor, using LocaleContextHolder's locale * as default locale. @@ -62,6 +64,7 @@ public class MessageSourceAccessor { this.defaultLocale = defaultLocale; } + /** * Return the default locale to use if no explicit locale has been given. *

The default implementation returns the default locale passed into the diff --git a/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java b/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java index 06bc24f4bd..dd6affb72b 100644 --- a/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java +++ b/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java @@ -31,6 +31,7 @@ import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySources; import org.springframework.core.env.PropertySourcesPropertyResolver; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringValueResolver; @@ -75,10 +76,13 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties"; + @Nullable private MutablePropertySources propertySources; + @Nullable private PropertySources appliedPropertySources; + @Nullable private Environment environment; diff --git a/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java index 92d9563b03..e5f5f1a6c0 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java +++ b/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java @@ -92,6 +92,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased private static final String XML_SUFFIX = ".xml"; + @Nullable private Properties fileEncodings; private boolean concurrentRefresh = true; @@ -549,6 +550,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased */ protected class PropertiesHolder { + @Nullable private final Properties properties; private final long fileTimestamp; diff --git a/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java index cded2a7598..93f1a68c37 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java +++ b/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java @@ -36,6 +36,7 @@ import java.util.Set; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** @@ -66,8 +67,10 @@ import org.springframework.util.ClassUtils; */ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSource implements BeanClassLoaderAware { + @Nullable private ClassLoader bundleClassLoader; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** @@ -77,8 +80,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou * This allows for very efficient hash lookups, significantly faster * than the ResourceBundle class's own cache. */ - private final Map> cachedResourceBundles = - new HashMap<>(); + private final Map> cachedResourceBundles = new HashMap<>(); /** * Cache to hold already generated MessageFormats. @@ -88,8 +90,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou * very efficient hash lookups without concatenated keys. * @see #getMessageFormat */ - private final Map>> cachedBundleMessageFormats = - new HashMap<>(); + private final Map>> cachedBundleMessageFormats = new HashMap<>(); /** @@ -109,6 +110,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou *

Default is the containing BeanFactory's bean ClassLoader. * @see #setBundleClassLoader */ + @Nullable protected ClassLoader getBundleClassLoader() { return (this.bundleClassLoader != null ? this.bundleClassLoader : this.beanClassLoader); } @@ -214,7 +216,9 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou * @see #getBundleClassLoader() */ protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException { - return ResourceBundle.getBundle(basename, locale, getBundleClassLoader(), new MessageSourceControl()); + ClassLoader classLoader = getBundleClassLoader(); + Assert.state(classLoader != null, "No bundle ClassLoader set"); + return ResourceBundle.getBundle(basename, locale, classLoader, new MessageSourceControl()); } /** diff --git a/spring-context/src/main/java/org/springframework/context/weaving/AspectJWeavingEnabler.java b/spring-context/src/main/java/org/springframework/context/weaving/AspectJWeavingEnabler.java index ec5627bf07..5cb8a6194b 100644 --- a/spring-context/src/main/java/org/springframework/context/weaving/AspectJWeavingEnabler.java +++ b/spring-context/src/main/java/org/springframework/context/weaving/AspectJWeavingEnabler.java @@ -78,7 +78,9 @@ public class AspectJWeavingEnabler * @param weaverToUse the LoadTimeWeaver to apply to (or {@code null} for a default weaver) * @param beanClassLoader the class loader to create a default weaver for (if necessary) */ - public static void enableAspectJWeaving(@Nullable LoadTimeWeaver weaverToUse, ClassLoader beanClassLoader) { + public static void enableAspectJWeaving( + @Nullable LoadTimeWeaver weaverToUse, @Nullable ClassLoader beanClassLoader) { + if (weaverToUse == null) { if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) { weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader); diff --git a/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java b/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java index 1299a21652..c5a7305052 100644 --- a/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java +++ b/spring-context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java @@ -33,6 +33,7 @@ import org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver; import org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver; import org.springframework.instrument.classloading.websphere.WebSphereLoadTimeWeaver; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Default {@link LoadTimeWeaver} bean for use in an application context, @@ -58,6 +59,7 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private LoadTimeWeaver loadTimeWeaver; @@ -68,6 +70,7 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo setBeanClassLoader(beanClassLoader); } + @Override public void setBeanClassLoader(ClassLoader classLoader) { LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader); @@ -148,16 +151,19 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo @Override public void addTransformer(ClassFileTransformer transformer) { + Assert.state(this.loadTimeWeaver != null, "Not initialized"); this.loadTimeWeaver.addTransformer(transformer); } @Override public ClassLoader getInstrumentableClassLoader() { + Assert.state(this.loadTimeWeaver != null, "Not initialized"); return this.loadTimeWeaver.getInstrumentableClassLoader(); } @Override public ClassLoader getThrowawayClassLoader() { + Assert.state(this.loadTimeWeaver != null, "Not initialized"); return this.loadTimeWeaver.getThrowawayClassLoader(); } diff --git a/spring-context/src/main/java/org/springframework/context/weaving/LoadTimeWeaverAwareProcessor.java b/spring-context/src/main/java/org/springframework/context/weaving/LoadTimeWeaverAwareProcessor.java index 22ceb478ec..b426a702b6 100644 --- a/spring-context/src/main/java/org/springframework/context/weaving/LoadTimeWeaverAwareProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/weaving/LoadTimeWeaverAwareProcessor.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. @@ -43,8 +43,10 @@ import org.springframework.util.Assert; */ public class LoadTimeWeaverAwareProcessor implements BeanPostProcessor, BeanFactoryAware { + @Nullable private LoadTimeWeaver loadTimeWeaver; + @Nullable private BeanFactory beanFactory; diff --git a/spring-context/src/main/java/org/springframework/ejb/access/AbstractSlsbInvokerInterceptor.java b/spring-context/src/main/java/org/springframework/ejb/access/AbstractSlsbInvokerInterceptor.java index 7f6ec9a15b..178240fe10 100644 --- a/spring-context/src/main/java/org/springframework/ejb/access/AbstractSlsbInvokerInterceptor.java +++ b/spring-context/src/main/java/org/springframework/ejb/access/AbstractSlsbInvokerInterceptor.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. @@ -51,11 +51,13 @@ public abstract class AbstractSlsbInvokerInterceptor extends JndiObjectLocator * The EJB's home object, potentially cached. * The type must be Object as it could be either EJBHome or EJBLocalHome. */ + @Nullable private Object cachedHome; /** * The no-arg create() method required on EJB homes, potentially cached. */ + @Nullable private Method createMethod; private final Object homeMonitor = new Object(); diff --git a/spring-context/src/main/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBean.java b/spring-context/src/main/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBean.java index 6b8419c615..0a73db46d2 100644 --- a/spring-context/src/main/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBean.java @@ -21,6 +21,7 @@ import javax.naming.NamingException; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -52,11 +53,14 @@ public class LocalStatelessSessionProxyFactoryBean extends LocalSlsbInvokerInter implements FactoryBean, BeanClassLoaderAware { /** The business interface of the EJB we're proxying */ + @Nullable private Class businessInterface; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** EJBLocalObject */ + @Nullable private Object proxy; @@ -73,6 +77,7 @@ public class LocalStatelessSessionProxyFactoryBean extends LocalSlsbInvokerInter /** * Return the business interface of the EJB we're proxying. */ + @Nullable public Class getBusinessInterface() { return this.businessInterface; } diff --git a/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptor.java b/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptor.java index 33e3c8cf3d..bf7aa03b14 100644 --- a/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptor.java +++ b/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteSlsbInvokerInterceptor.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. @@ -25,6 +25,7 @@ import javax.naming.NamingException; import org.aopalliance.intercept.MethodInvocation; import org.springframework.beans.factory.DisposableBean; +import org.springframework.lang.Nullable; import org.springframework.remoting.RemoteLookupFailureException; import org.springframework.remoting.rmi.RmiClientInterceptorUtils; @@ -66,6 +67,7 @@ public class SimpleRemoteSlsbInvokerInterceptor extends AbstractRemoteSlsbInvoke private boolean cacheSessionBean = false; + @Nullable private Object beanInstance; private final Object beanInstanceMonitor = new Object(); diff --git a/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBean.java b/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBean.java index dea7272692..2252b2b9aa 100644 --- a/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBean.java @@ -21,6 +21,7 @@ import javax.naming.NamingException; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -62,11 +63,14 @@ public class SimpleRemoteStatelessSessionProxyFactoryBean extends SimpleRemoteSl implements FactoryBean, BeanClassLoaderAware { /** The business interface of the EJB we're proxying */ + @Nullable private Class businessInterface; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** EJBObject */ + @Nullable private Object proxy; @@ -87,6 +91,7 @@ public class SimpleRemoteStatelessSessionProxyFactoryBean extends SimpleRemoteSl /** * Return the business interface of the EJB we're proxying. */ + @Nullable public Class getBusinessInterface() { return this.businessInterface; } diff --git a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java index 3c89616c82..689e097a7d 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.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. @@ -28,6 +28,7 @@ import java.util.TimeZone; import org.springframework.format.Formatter; import org.springframework.format.annotation.DateTimeFormat.ISO; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -55,14 +56,18 @@ public class DateFormatter implements Formatter { } + @Nullable private String pattern; private int style = DateFormat.DEFAULT; + @Nullable private String stylePattern; + @Nullable private ISO iso; + @Nullable private TimeZone timeZone; private boolean lenient = false; diff --git a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java index 00d20d68e2..d9c2e69e06 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.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,6 +23,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.format.FormatterRegistrar; import org.springframework.format.FormatterRegistry; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -42,6 +43,7 @@ import org.springframework.util.Assert; */ public class DateFormatterRegistrar implements FormatterRegistrar { + @Nullable private DateFormatter dateFormatter; diff --git a/spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java b/spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java index 53c7246478..56e9c32559 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java @@ -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. @@ -24,6 +24,7 @@ import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.springframework.format.annotation.DateTimeFormat.ISO; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -44,12 +45,16 @@ import org.springframework.util.StringUtils; */ public class DateTimeFormatterFactory { + @Nullable private String pattern; + @Nullable private ISO iso; + @Nullable private String style; + @Nullable private TimeZone timeZone; diff --git a/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeContext.java b/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeContext.java index 4c8c2a0090..f49a4443f0 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeContext.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeContext.java @@ -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. @@ -39,8 +39,10 @@ import org.springframework.lang.Nullable; */ public class JodaTimeContext { + @Nullable private Chronology chronology; + @Nullable private DateTimeZone timeZone; diff --git a/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeContext.java b/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeContext.java index 677348f4f9..80ec0c81ce 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeContext.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeContext.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. @@ -37,8 +37,10 @@ import org.springframework.lang.Nullable; */ public class DateTimeContext { + @Nullable private Chronology chronology; + @Nullable private ZoneId timeZone; diff --git a/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterFactory.java b/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterFactory.java index 0cd5341ff0..d8d85c6ce2 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterFactory.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterFactory.java @@ -46,14 +46,19 @@ import org.springframework.util.StringUtils; */ public class DateTimeFormatterFactory { + @Nullable private String pattern; + @Nullable private ISO iso; + @Nullable private FormatStyle dateStyle; + @Nullable private FormatStyle timeStyle; + @Nullable private TimeZone timeZone; diff --git a/spring-context/src/main/java/org/springframework/format/number/CurrencyStyleFormatter.java b/spring-context/src/main/java/org/springframework/format/number/CurrencyStyleFormatter.java index a3d75c59c9..b6432fc728 100644 --- a/spring-context/src/main/java/org/springframework/format/number/CurrencyStyleFormatter.java +++ b/spring-context/src/main/java/org/springframework/format/number/CurrencyStyleFormatter.java @@ -24,6 +24,8 @@ import java.text.ParseException; import java.util.Currency; import java.util.Locale; +import org.springframework.lang.Nullable; + /** * A BigDecimal formatter for number values in currency style. * @@ -41,10 +43,13 @@ public class CurrencyStyleFormatter extends AbstractNumberFormatter { private int fractionDigits = 2; + @Nullable private RoundingMode roundingMode; + @Nullable private Currency currency; + @Nullable private String pattern; diff --git a/spring-context/src/main/java/org/springframework/format/number/NumberStyleFormatter.java b/spring-context/src/main/java/org/springframework/format/number/NumberStyleFormatter.java index e92c5f343a..16f67973a2 100644 --- a/spring-context/src/main/java/org/springframework/format/number/NumberStyleFormatter.java +++ b/spring-context/src/main/java/org/springframework/format/number/NumberStyleFormatter.java @@ -20,6 +20,8 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Locale; +import org.springframework.lang.Nullable; + /** * A general-purpose number formatter using NumberFormat's number style. * @@ -36,6 +38,7 @@ import java.util.Locale; */ public class NumberStyleFormatter extends AbstractNumberFormatter { + @Nullable private String pattern; diff --git a/spring-context/src/main/java/org/springframework/format/number/money/MonetaryAmountFormatter.java b/spring-context/src/main/java/org/springframework/format/number/money/MonetaryAmountFormatter.java index 8d949ac45d..acac27a619 100644 --- a/spring-context/src/main/java/org/springframework/format/number/money/MonetaryAmountFormatter.java +++ b/spring-context/src/main/java/org/springframework/format/number/money/MonetaryAmountFormatter.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. @@ -22,6 +22,7 @@ import javax.money.format.MonetaryAmountFormat; import javax.money.format.MonetaryFormats; import org.springframework.format.Formatter; +import org.springframework.lang.Nullable; /** * Formatter for JSR-354 {@link javax.money.MonetaryAmount} values, @@ -34,6 +35,7 @@ import org.springframework.format.Formatter; */ public class MonetaryAmountFormatter implements Formatter { + @Nullable private String formatName; diff --git a/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java b/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java index c6377be933..8cf286a2a4 100644 --- a/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java +++ b/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java @@ -51,6 +51,7 @@ import org.springframework.util.StringValueResolver; public class FormattingConversionService extends GenericConversionService implements FormatterRegistry, EmbeddedValueResolverAware { + @Nullable private StringValueResolver embeddedValueResolver; private final Map cachedPrinters = new ConcurrentHashMap<>(64); diff --git a/spring-context/src/main/java/org/springframework/format/support/FormattingConversionServiceFactoryBean.java b/spring-context/src/main/java/org/springframework/format/support/FormattingConversionServiceFactoryBean.java index 2f5ae16930..491a7bf839 100644 --- a/spring-context/src/main/java/org/springframework/format/support/FormattingConversionServiceFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/format/support/FormattingConversionServiceFactoryBean.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. @@ -28,6 +28,7 @@ import org.springframework.format.FormatterRegistrar; import org.springframework.format.FormatterRegistry; import org.springframework.format.Parser; import org.springframework.format.Printer; +import org.springframework.lang.Nullable; import org.springframework.util.StringValueResolver; /** @@ -63,16 +64,21 @@ import org.springframework.util.StringValueResolver; public class FormattingConversionServiceFactoryBean implements FactoryBean, EmbeddedValueResolverAware, InitializingBean { + @Nullable private Set converters; + @Nullable private Set formatters; + @Nullable private Set formatterRegistrars; private boolean registerDefaultFormatters = true; + @Nullable private StringValueResolver embeddedValueResolver; + @Nullable private FormattingConversionService conversionService; @@ -134,17 +140,17 @@ public class FormattingConversionServiceFactoryBean public void afterPropertiesSet() { this.conversionService = new DefaultFormattingConversionService(this.embeddedValueResolver, this.registerDefaultFormatters); ConversionServiceFactory.registerConverters(this.converters, this.conversionService); - registerFormatters(); + registerFormatters(this.conversionService); } - private void registerFormatters() { + private void registerFormatters(FormattingConversionService conversionService) { if (this.formatters != null) { for (Object formatter : this.formatters) { if (formatter instanceof Formatter) { - this.conversionService.addFormatter((Formatter) formatter); + conversionService.addFormatter((Formatter) formatter); } else if (formatter instanceof AnnotationFormatterFactory) { - this.conversionService.addFormatterForFieldAnnotation((AnnotationFormatterFactory) formatter); + conversionService.addFormatterForFieldAnnotation((AnnotationFormatterFactory) formatter); } else { throw new IllegalArgumentException( @@ -154,7 +160,7 @@ public class FormattingConversionServiceFactoryBean } if (this.formatterRegistrars != null) { for (FormatterRegistrar registrar : this.formatterRegistrars) { - registrar.registerFormatters(this.conversionService); + registrar.registerFormatters(conversionService); } } } diff --git a/spring-context/src/main/java/org/springframework/instrument/classloading/InstrumentationLoadTimeWeaver.java b/spring-context/src/main/java/org/springframework/instrument/classloading/InstrumentationLoadTimeWeaver.java index 257266ec44..2dd21015d6 100644 --- a/spring-context/src/main/java/org/springframework/instrument/classloading/InstrumentationLoadTimeWeaver.java +++ b/spring-context/src/main/java/org/springframework/instrument/classloading/InstrumentationLoadTimeWeaver.java @@ -54,8 +54,10 @@ public class InstrumentationLoadTimeWeaver implements LoadTimeWeaver { InstrumentationLoadTimeWeaver.class.getClassLoader()); + @Nullable private final ClassLoader classLoader; + @Nullable private final Instrumentation instrumentation; private final List transformers = new ArrayList<>(4); @@ -115,7 +117,7 @@ public class InstrumentationLoadTimeWeaver implements LoadTimeWeaver { */ public void removeTransformers() { synchronized (this.transformers) { - if (!this.transformers.isEmpty()) { + if (this.instrumentation != null && !this.transformers.isEmpty()) { for (int i = this.transformers.size() - 1; i >= 0; i--) { this.instrumentation.removeTransformer(this.transformers.get(i)); } @@ -167,9 +169,12 @@ public class InstrumentationLoadTimeWeaver implements LoadTimeWeaver { private final ClassFileTransformer targetTransformer; + @Nullable private final ClassLoader targetClassLoader; - public FilteringClassFileTransformer(ClassFileTransformer targetTransformer, ClassLoader targetClassLoader) { + public FilteringClassFileTransformer( + ClassFileTransformer targetTransformer, @Nullable ClassLoader targetClassLoader) { + this.targetTransformer = targetTransformer; this.targetClassLoader = targetClassLoader; } @@ -179,7 +184,7 @@ public class InstrumentationLoadTimeWeaver implements LoadTimeWeaver { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { - if (!this.targetClassLoader.equals(loader)) { + if (this.targetClassLoader != loader) { return null; } return this.targetTransformer.transform( diff --git a/spring-context/src/main/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaver.java b/spring-context/src/main/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaver.java index 90d90cd34d..68ba793371 100644 --- a/spring-context/src/main/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaver.java +++ b/spring-context/src/main/java/org/springframework/instrument/classloading/ReflectiveLoadTimeWeaver.java @@ -76,6 +76,7 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver { private final Method addTransformerMethod; + @Nullable private final Method getThrowawayClassLoaderMethod; @@ -97,22 +98,26 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver { public ReflectiveLoadTimeWeaver(@Nullable ClassLoader classLoader) { Assert.notNull(classLoader, "ClassLoader must not be null"); this.classLoader = classLoader; - this.addTransformerMethod = ClassUtils.getMethodIfAvailable( + + Method addTransformerMethod = ClassUtils.getMethodIfAvailable( this.classLoader.getClass(), ADD_TRANSFORMER_METHOD_NAME, ClassFileTransformer.class); - if (this.addTransformerMethod == null) { + if (addTransformerMethod == null) { throw new IllegalStateException( "ClassLoader [" + classLoader.getClass().getName() + "] does NOT provide an " + "'addTransformer(ClassFileTransformer)' method."); } - this.getThrowawayClassLoaderMethod = ClassUtils.getMethodIfAvailable( + this.addTransformerMethod = addTransformerMethod; + + Method getThrowawayClassLoaderMethod = ClassUtils.getMethodIfAvailable( this.classLoader.getClass(), GET_THROWAWAY_CLASS_LOADER_METHOD_NAME); // getThrowawayClassLoader method is optional - if (this.getThrowawayClassLoaderMethod == null) { + if (getThrowawayClassLoaderMethod == null) { if (logger.isInfoEnabled()) { logger.info("The ClassLoader [" + classLoader.getClass().getName() + "] does NOT provide a " + "'getThrowawayClassLoader()' method; SimpleThrowawayClassLoader will be used instead."); } } + this.getThrowawayClassLoaderMethod = getThrowawayClassLoaderMethod; } diff --git a/spring-context/src/main/java/org/springframework/instrument/classloading/WeavingTransformer.java b/spring-context/src/main/java/org/springframework/instrument/classloading/WeavingTransformer.java index 6e9f2ad470..48264329d3 100644 --- a/spring-context/src/main/java/org/springframework/instrument/classloading/WeavingTransformer.java +++ b/spring-context/src/main/java/org/springframework/instrument/classloading/WeavingTransformer.java @@ -39,6 +39,7 @@ import org.springframework.util.Assert; */ public class WeavingTransformer { + @Nullable private final ClassLoader classLoader; private final List transformers = new ArrayList<>(); diff --git a/spring-context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java b/spring-context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java index 131e39062a..bee9d2e86d 100644 --- a/spring-context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java +++ b/spring-context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java @@ -67,6 +67,7 @@ public class JBossLoadTimeWeaver implements LoadTimeWeaver { public JBossLoadTimeWeaver(@Nullable ClassLoader classLoader) { Assert.notNull(classLoader, "ClassLoader must not be null"); this.classLoader = classLoader; + try { Field transformer = ReflectionUtils.findField(classLoader.getClass(), "transformer"); if (transformer == null) { @@ -74,20 +75,23 @@ public class JBossLoadTimeWeaver implements LoadTimeWeaver { classLoader.getClass().getName()); } transformer.setAccessible(true); + this.delegatingTransformer = transformer.get(classLoader); if (!this.delegatingTransformer.getClass().getName().equals(DELEGATING_TRANSFORMER_CLASS_NAME)) { throw new IllegalStateException( "Transformer not of the expected type DelegatingClassFileTransformer: " + this.delegatingTransformer.getClass().getName()); } - this.addTransformer = ReflectionUtils.findMethod(this.delegatingTransformer.getClass(), + + Method addTransformer = ReflectionUtils.findMethod(this.delegatingTransformer.getClass(), "addTransformer", ClassFileTransformer.class); - if (this.addTransformer == null) { + if (addTransformer == null) { throw new IllegalArgumentException( "Could not find 'addTransformer' method on JBoss DelegatingClassFileTransformer: " + this.delegatingTransformer.getClass().getName()); } - this.addTransformer.setAccessible(true); + addTransformer.setAccessible(true); + this.addTransformer = addTransformer; } catch (Throwable ex) { throw new IllegalStateException("Could not initialize JBoss LoadTimeWeaver", ex); diff --git a/spring-context/src/main/java/org/springframework/jmx/access/ConnectorDelegate.java b/spring-context/src/main/java/org/springframework/jmx/access/ConnectorDelegate.java index 8b408254dc..1a700c76c1 100644 --- a/spring-context/src/main/java/org/springframework/jmx/access/ConnectorDelegate.java +++ b/spring-context/src/main/java/org/springframework/jmx/access/ConnectorDelegate.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. @@ -40,6 +40,7 @@ class ConnectorDelegate { private static final Log logger = LogFactory.getLog(ConnectorDelegate.class); + @Nullable private JMXConnector connector; diff --git a/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java b/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java index 25f6924d62..984750caa5 100644 --- a/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java +++ b/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java @@ -23,6 +23,7 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.management.Attribute; @@ -62,6 +63,7 @@ import org.springframework.core.ResolvableType; import org.springframework.jmx.support.JmxUtils; import org.springframework.jmx.support.ObjectNameManager; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; @@ -93,35 +95,44 @@ public class MBeanClientInterceptor /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private MBeanServerConnection server; + @Nullable private JMXServiceURL serviceUrl; + @Nullable private Map environment; + @Nullable private String agentId; private boolean connectOnStartup = true; private boolean refreshOnConnectFailure = false; + @Nullable private ObjectName objectName; private boolean useStrictCasing = true; + @Nullable private Class managementInterface; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private final ConnectorDelegate connector = new ConnectorDelegate(); + @Nullable private MBeanServerConnection serverToUse; + @Nullable private MBeanServerInvocationHandler invocationHandler; - private Map allowedAttributes; + private Map allowedAttributes = Collections.emptyMap(); - private Map allowedOperations; + private Map allowedOperations = Collections.emptyMap(); private final Map signatureCache = new HashMap<>(); @@ -158,6 +169,7 @@ public class MBeanClientInterceptor * "environment[myKey]". This is particularly useful for * adding or overriding entries in child bean definitions. */ + @Nullable public Map getEnvironment() { return this.environment; } @@ -231,7 +243,7 @@ public class MBeanClientInterceptor } @Override - public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) { + public void setBeanClassLoader(ClassLoader beanClassLoader) { this.beanClassLoader = beanClassLoader; } @@ -266,6 +278,7 @@ public class MBeanClientInterceptor } this.invocationHandler = null; if (this.useStrictCasing) { + Assert.state(this.objectName != null, "No ObjectName set"); // Use the JDK's own MBeanServerInvocationHandler, in particular for native MXBean support. this.invocationHandler = new MBeanServerInvocationHandler(this.serverToUse, this.objectName, (this.managementInterface != null && JMX.isMXBeanInterface(this.managementInterface))); @@ -273,7 +286,7 @@ public class MBeanClientInterceptor else { // Non-strict casing can only be achieved through custom invocation handling. // Only partial MXBean support available! - retrieveMBeanInfo(); + retrieveMBeanInfo(this.serverToUse); } } } @@ -282,9 +295,9 @@ public class MBeanClientInterceptor * This information is used by the proxy when determining whether an invocation matches * a valid operation or attribute on the management interface of the managed resource. */ - private void retrieveMBeanInfo() throws MBeanInfoRetrievalException { + private void retrieveMBeanInfo(MBeanServerConnection server) throws MBeanInfoRetrievalException { try { - MBeanInfo info = this.serverToUse.getMBeanInfo(this.objectName); + MBeanInfo info = server.getMBeanInfo(this.objectName); MBeanAttributeInfo[] attributeInfo = info.getAttributes(); this.allowedAttributes = new HashMap<>(attributeInfo.length); @@ -401,7 +414,7 @@ public class MBeanClientInterceptor protected Object doInvoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); try { - Object result = null; + Object result; if (this.invocationHandler != null) { result = this.invocationHandler.invoke(invocation.getThis(), method, invocation.getArguments()); } @@ -468,6 +481,8 @@ public class MBeanClientInterceptor private Object invokeAttribute(PropertyDescriptor pd, MethodInvocation invocation) throws JMException, IOException { + Assert.state(this.serverToUse != null, "No MBeanServerConnection available"); + String attributeName = JmxUtils.getAttributeName(pd, this.useStrictCasing); MBeanAttributeInfo inf = this.allowedAttributes.get(attributeName); // If no attribute is returned, we know that it is not defined in the @@ -476,6 +491,7 @@ public class MBeanClientInterceptor throw new InvalidInvocationException( "Attribute '" + pd.getName() + "' is not exposed on the management interface"); } + if (invocation.getMethod().equals(pd.getReadMethod())) { if (inf.isReadable()) { return this.serverToUse.getAttribute(this.objectName, attributeName); @@ -507,13 +523,16 @@ public class MBeanClientInterceptor * @return the value returned by the method invocation. */ private Object invokeOperation(Method method, Object[] args) throws JMException, IOException { + Assert.state(this.serverToUse != null, "No MBeanServerConnection available"); + MethodCacheKey key = new MethodCacheKey(method.getName(), method.getParameterTypes()); MBeanOperationInfo info = this.allowedOperations.get(key); if (info == null) { throw new InvalidInvocationException("Operation '" + method.getName() + "' is not exposed on the management interface"); } - String[] signature = null; + + String[] signature; synchronized (this.signatureCache) { signature = this.signatureCache.get(method); if (signature == null) { @@ -521,6 +540,7 @@ public class MBeanClientInterceptor this.signatureCache.put(method, signature); } } + return this.serverToUse.invoke(this.objectName, method.getName(), args, signature); } diff --git a/spring-context/src/main/java/org/springframework/jmx/access/MBeanProxyFactoryBean.java b/spring-context/src/main/java/org/springframework/jmx/access/MBeanProxyFactoryBean.java index b80b5e7b2c..d2c4f96d8f 100644 --- a/spring-context/src/main/java/org/springframework/jmx/access/MBeanProxyFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/jmx/access/MBeanProxyFactoryBean.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.jmx.MBeanServerNotFoundException; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -48,10 +49,13 @@ import org.springframework.util.ClassUtils; public class MBeanProxyFactoryBean extends MBeanClientInterceptor implements FactoryBean, BeanClassLoaderAware, InitializingBean { + @Nullable private Class proxyInterface; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private Object mbeanProxy; diff --git a/spring-context/src/main/java/org/springframework/jmx/access/NotificationListenerRegistrar.java b/spring-context/src/main/java/org/springframework/jmx/access/NotificationListenerRegistrar.java index c5853aa6ed..ead3ff9f53 100644 --- a/spring-context/src/main/java/org/springframework/jmx/access/NotificationListenerRegistrar.java +++ b/spring-context/src/main/java/org/springframework/jmx/access/NotificationListenerRegistrar.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,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.jmx.JmxException; import org.springframework.jmx.MBeanServerNotFoundException; import org.springframework.jmx.support.NotificationListenerHolder; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; /** @@ -51,16 +52,21 @@ public class NotificationListenerRegistrar extends NotificationListenerHolder /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); - private MBeanServerConnection server; - - private JMXServiceURL serviceUrl; - - private Map environment; - - private String agentId; - private final ConnectorDelegate connector = new ConnectorDelegate(); + @Nullable + private MBeanServerConnection server; + + @Nullable + private JMXServiceURL serviceUrl; + + @Nullable + private Map environment; + + @Nullable + private String agentId; + + @Nullable private ObjectName[] actualObjectNames; @@ -87,6 +93,7 @@ public class NotificationListenerRegistrar extends NotificationListenerHolder * "environment[myKey]". This is particularly useful for * adding or overriding entries in child bean definitions. */ + @Nullable public Map getEnvironment() { return this.environment; } @@ -133,12 +140,14 @@ public class NotificationListenerRegistrar extends NotificationListenerHolder } try { this.actualObjectNames = getResolvedObjectNames(); - if (logger.isDebugEnabled()) { - logger.debug("Registering NotificationListener for MBeans " + Arrays.asList(this.actualObjectNames)); - } - for (ObjectName actualObjectName : this.actualObjectNames) { - this.server.addNotificationListener( - actualObjectName, getNotificationListener(), getNotificationFilter(), getHandback()); + if (this.actualObjectNames != null) { + if (logger.isDebugEnabled()) { + logger.debug("Registering NotificationListener for MBeans " + Arrays.asList(this.actualObjectNames)); + } + for (ObjectName actualObjectName : this.actualObjectNames) { + this.server.addNotificationListener( + actualObjectName, getNotificationListener(), getNotificationFilter(), getHandback()); + } } } catch (IOException ex) { @@ -156,7 +165,7 @@ public class NotificationListenerRegistrar extends NotificationListenerHolder @Override public void destroy() { try { - if (this.actualObjectNames != null) { + if (this.server != null && this.actualObjectNames != null) { for (ObjectName actualObjectName : this.actualObjectNames) { try { this.server.removeNotificationListener( diff --git a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java index d4b39c81b5..97d567b416 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java @@ -141,9 +141,11 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo private static final Constants constants = new Constants(MBeanExporter.class); /** The beans to be exposed as JMX managed resources, with JMX names as keys */ + @Nullable private Map beans; /** The autodetect mode to use for this MBeanExporter */ + @Nullable private Integer autodetectMode; /** Whether to eagerly initialize candidate beans when autodetecting MBeans */ @@ -165,19 +167,22 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo private Set excludedBeans = new HashSet<>(); /** The MBeanExporterListeners registered with this exporter. */ + @Nullable private MBeanExporterListener[] listeners; /** The NotificationListeners to register for the MBeans registered by this exporter */ + @Nullable private NotificationListenerBean[] notificationListeners; /** Map of actually registered NotificationListeners */ - private final Map registeredNotificationListeners = - new LinkedHashMap<>(); + private final Map registeredNotificationListeners = new LinkedHashMap<>(); /** Stores the ClassLoader to use for generating lazy-init proxies */ + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** Stores the BeanFactory for use in autodetection process */ + @Nullable private ListableBeanFactory beanFactory; @@ -534,18 +539,17 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) { // Autodetect any beans that are already MBeans. logger.debug("Autodetecting user-defined JMX MBeans"); - autodetectMBeans(); + autodetect(this.beans, (beanClass, beanName) -> isMBean(beanClass)); } // Allow the assembler a chance to vote for bean inclusion. if ((mode == AUTODETECT_ASSEMBLER || mode == AUTODETECT_ALL) && this.assembler instanceof AutodetectCapableMBeanInfoAssembler) { - autodetectBeans((AutodetectCapableMBeanInfoAssembler) this.assembler); + autodetect(this.beans, ((AutodetectCapableMBeanInfoAssembler) this.assembler)::includeBean); } } if (!this.beans.isEmpty()) { - this.beans.forEach((beanName, instance) -> - registerBeanNameOrInstance(instance, beanName)); + this.beans.forEach((beanName, instance) -> registerBeanNameOrInstance(instance, beanName)); } } @@ -699,6 +703,8 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo * with the {@code MBeanServer} */ private ObjectName registerLazyInit(String beanName, String beanKey) throws JMException { + Assert.state(this.beanFactory != null, "No BeanFactory set"); + ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setProxyTargetClass(true); proxyFactory.setFrozen(true); @@ -863,26 +869,6 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo // Autodetection process //--------------------------------------------------------------------- - /** - * Invoked when using an {@code AutodetectCapableMBeanInfoAssembler}. - * Gives the assembler the opportunity to add additional beans from the - * {@code BeanFactory} to the list of beans to be exposed via JMX. - *

This implementation prevents a bean from being added to the list - * automatically if it has already been added manually, and it prevents - * certain internal classes from being registered automatically. - */ - private void autodetectBeans(final AutodetectCapableMBeanInfoAssembler assembler) { - autodetect((beanClass, beanName) -> assembler.includeBean(beanClass, beanName)); - } - - /** - * Attempts to detect any beans defined in the {@code ApplicationContext} that are - * valid MBeans and registers them automatically with the {@code MBeanServer}. - */ - private void autodetectMBeans() { - autodetect((beanClass, beanName) -> isMBean(beanClass)); - } - /** * Performs the actual autodetection process, delegating to an * {@code AutodetectCallback} instance to vote on the inclusion of a @@ -890,12 +876,14 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo * @param callback the {@code AutodetectCallback} to use when deciding * whether to include a bean or not */ - private void autodetect(AutodetectCallback callback) { + private void autodetect(Map beans, AutodetectCallback callback) { + Assert.state(this.beanFactory != null, "No BeanFactory set"); Set beanNames = new LinkedHashSet<>(this.beanFactory.getBeanDefinitionCount()); beanNames.addAll(Arrays.asList(this.beanFactory.getBeanDefinitionNames())); if (this.beanFactory instanceof ConfigurableBeanFactory) { beanNames.addAll(Arrays.asList(((ConfigurableBeanFactory) this.beanFactory).getSingletonNames())); } + for (String beanName : beanNames) { if (!isExcluded(beanName) && !isBeanDefinitionAbstract(this.beanFactory, beanName)) { try { @@ -903,11 +891,11 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo if (beanClass != null && callback.include(beanClass, beanName)) { boolean lazyInit = isBeanDefinitionLazyInit(this.beanFactory, beanName); Object beanInstance = (!lazyInit ? this.beanFactory.getBean(beanName) : null); - if (!ScopedProxyUtils.isScopedTarget(beanName) && !this.beans.containsValue(beanName) && + if (!ScopedProxyUtils.isScopedTarget(beanName) && !beans.containsValue(beanName) && (beanInstance == null || - !CollectionUtils.containsInstance(this.beans.values(), beanInstance))) { + !CollectionUtils.containsInstance(beans.values(), beanInstance))) { // Not already registered for JMX exposure. - this.beans.put(beanName, (beanInstance != null ? beanInstance : beanName)); + beans.put(beanName, (beanInstance != null ? beanInstance : beanName)); if (logger.isInfoEnabled()) { logger.info("Bean with name '" + beanName + "' has been autodetected for JMX exposure"); } @@ -970,6 +958,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo */ private void registerNotificationListeners() throws MBeanExportException { if (this.notificationListeners != null) { + Assert.state(this.server != null, "No MBeanServer available"); for (NotificationListenerBean bean : this.notificationListeners) { try { ObjectName[] mappedObjectNames = bean.getResolvedObjectNames(); @@ -996,19 +985,21 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo * from the {@link MBeanServer}. */ private void unregisterNotificationListeners() { - this.registeredNotificationListeners.forEach((bean, mappedObjectNames) -> { - for (ObjectName mappedObjectName : mappedObjectNames) { - try { - this.server.removeNotificationListener(mappedObjectName, bean.getNotificationListener(), - bean.getNotificationFilter(), bean.getHandback()); - } - catch (Throwable ex) { - if (logger.isDebugEnabled()) { - logger.debug("Unable to unregister NotificationListener", ex); + if (this.server != null) { + this.registeredNotificationListeners.forEach((bean, mappedObjectNames) -> { + for (ObjectName mappedObjectName : mappedObjectNames) { + try { + this.server.removeNotificationListener(mappedObjectName, bean.getNotificationListener(), + bean.getNotificationFilter(), bean.getHandback()); + } + catch (Throwable ex) { + if (logger.isDebugEnabled()) { + logger.debug("Unable to unregister NotificationListener", ex); + } } } - } - }); + }); + } this.registeredNotificationListeners.clear(); } @@ -1096,8 +1087,10 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo @SuppressWarnings("serial") private class NotificationPublisherAwareLazyTargetSource extends LazyInitTargetSource { + @Nullable private ModelMBean modelMBean; + @Nullable private ObjectName objectName; public void setModelMBean(ModelMBean modelMBean) { @@ -1123,6 +1116,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo @Override protected void postProcessTargetObject(Object targetObject) { + Assert.state(this.modelMBean != null && this.objectName != null, "Not initialized"); injectNotificationPublisherIfNecessary(targetObject, this.modelMBean, this.objectName); } } diff --git a/spring-context/src/main/java/org/springframework/jmx/export/NotificationListenerBean.java b/spring-context/src/main/java/org/springframework/jmx/export/NotificationListenerBean.java index 53339d84e4..a943b7849e 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/NotificationListenerBean.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/NotificationListenerBean.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. @@ -24,8 +24,7 @@ import org.springframework.util.Assert; /** * Helper class that aggregates a {@link javax.management.NotificationListener}, - * a {@link javax.management.NotificationFilter}, and an arbitrary handback - * object. + * a {@link javax.management.NotificationFilter}, and an arbitrary handback object. * *

Also provides support for associating the encapsulated * {@link javax.management.NotificationListener} with any number of diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java index 00dbabf8e6..7beb0eb02e 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java @@ -50,6 +50,7 @@ import org.springframework.util.StringValueResolver; */ public class AnnotationJmxAttributeSource implements JmxAttributeSource, BeanFactoryAware { + @Nullable private StringValueResolver embeddedValueResolver; diff --git a/spring-context/src/main/java/org/springframework/jmx/export/assembler/AbstractConfigurableMBeanInfoAssembler.java b/spring-context/src/main/java/org/springframework/jmx/export/assembler/AbstractConfigurableMBeanInfoAssembler.java index 9269126e40..940bf1b21a 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/assembler/AbstractConfigurableMBeanInfoAssembler.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/assembler/AbstractConfigurableMBeanInfoAssembler.java @@ -25,6 +25,7 @@ import javax.management.modelmbean.ModelMBeanNotificationInfo; import org.springframework.jmx.export.metadata.JmxMetadataUtils; import org.springframework.jmx.export.metadata.ManagedNotification; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -37,10 +38,10 @@ import org.springframework.util.StringUtils; */ public abstract class AbstractConfigurableMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssembler { + @Nullable private ModelMBeanNotificationInfo[] notificationInfos; - private final Map notificationInfoMappings = - new HashMap<>(); + private final Map notificationInfoMappings = new HashMap<>(); public void setNotificationInfos(ManagedNotification[] notificationInfos) { diff --git a/spring-context/src/main/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssembler.java b/spring-context/src/main/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssembler.java index f48e0e2656..f16f38e813 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssembler.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssembler.java @@ -61,14 +61,18 @@ import org.springframework.util.StringUtils; public class InterfaceBasedMBeanInfoAssembler extends AbstractConfigurableMBeanInfoAssembler implements BeanClassLoaderAware, InitializingBean { + @Nullable private Class[] managedInterfaces; /** Mappings of bean keys to an array of classes */ + @Nullable private Properties interfaceMappings; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** Mappings of bean keys to an array of classes */ + @Nullable private Map[]> resolvedInterfaceMappings; diff --git a/spring-context/src/main/java/org/springframework/jmx/export/assembler/MetadataMBeanInfoAssembler.java b/spring-context/src/main/java/org/springframework/jmx/export/assembler/MetadataMBeanInfoAssembler.java index a715489f05..1fa216ee62 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/assembler/MetadataMBeanInfoAssembler.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/assembler/MetadataMBeanInfoAssembler.java @@ -40,12 +40,12 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** - * Implementation of the {@link MBeanInfoAssembler} - * interface that reads the management interface information from source level metadata. + * Implementation of the {@link MBeanInfoAssembler} interface that reads + * the management interface information from source level metadata. * *

Uses the {@link JmxAttributeSource} strategy interface, so that * metadata can be read using any supported implementation. Out of the box, - * Spring provides an implementation based on JDK 1.5+ annotations, + * Spring provides an implementation based on annotations: * {@code AnnotationJmxAttributeSource}. * * @author Rob Harrop @@ -58,6 +58,7 @@ import org.springframework.util.StringUtils; public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssembler implements AutodetectCapableMBeanInfoAssembler, InitializingBean { + @Nullable private JmxAttributeSource attributeSource; @@ -96,6 +97,11 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem } } + private JmxAttributeSource obtainAttributeSource() { + Assert.state(this.attributeSource != null, "No JmxAttributeSource set"); + return this.attributeSource; + } + /** * Throws an IllegalArgumentException if it encounters a JDK dynamic proxy. @@ -118,7 +124,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem */ @Override public boolean includeBean(Class beanClass, String beanName) { - return (this.attributeSource.getManagedResource(getClassToExpose(beanClass)) != null); + return (obtainAttributeSource().getManagedResource(getClassToExpose(beanClass)) != null); } /** @@ -164,14 +170,14 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem * Checks to see if the given Method has the {@code ManagedAttribute} attribute. */ private boolean hasManagedAttribute(Method method) { - return (this.attributeSource.getManagedAttribute(method) != null); + return (obtainAttributeSource().getManagedAttribute(method) != null); } /** * Checks to see if the given Method has the {@code ManagedMetric} attribute. */ private boolean hasManagedMetric(Method method) { - return (this.attributeSource.getManagedMetric(method) != null); + return (obtainAttributeSource().getManagedMetric(method) != null); } /** @@ -179,7 +185,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem * @param method the method to check */ private boolean hasManagedOperation(Method method) { - return (this.attributeSource.getManagedOperation(method) != null); + return (obtainAttributeSource().getManagedOperation(method) != null); } @@ -189,7 +195,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem */ @Override protected String getDescription(Object managedBean, String beanKey) { - ManagedResource mr = this.attributeSource.getManagedResource(getClassToExpose(managedBean)); + ManagedResource mr = obtainAttributeSource().getManagedResource(getClassToExpose(managedBean)); return (mr != null ? mr.getDescription() : ""); } @@ -204,9 +210,9 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem Method writeMethod = propertyDescriptor.getWriteMethod(); ManagedAttribute getter = - (readMethod != null ? this.attributeSource.getManagedAttribute(readMethod) : null); + (readMethod != null ? obtainAttributeSource().getManagedAttribute(readMethod) : null); ManagedAttribute setter = - (writeMethod != null ? this.attributeSource.getManagedAttribute(writeMethod) : null); + (writeMethod != null ? obtainAttributeSource().getManagedAttribute(writeMethod) : null); if (getter != null && StringUtils.hasText(getter.getDescription())) { return getter.getDescription(); @@ -215,7 +221,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem return setter.getDescription(); } - ManagedMetric metric = (readMethod != null ? this.attributeSource.getManagedMetric(readMethod) : null); + ManagedMetric metric = (readMethod != null ? obtainAttributeSource().getManagedMetric(readMethod) : null); if (metric != null && StringUtils.hasText(metric.getDescription())) { return metric.getDescription(); } @@ -231,18 +237,18 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem protected String getOperationDescription(Method method, String beanKey) { PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); if (pd != null) { - ManagedAttribute ma = this.attributeSource.getManagedAttribute(method); + ManagedAttribute ma = obtainAttributeSource().getManagedAttribute(method); if (ma != null && StringUtils.hasText(ma.getDescription())) { return ma.getDescription(); } - ManagedMetric metric = this.attributeSource.getManagedMetric(method); + ManagedMetric metric = obtainAttributeSource().getManagedMetric(method); if (metric != null && StringUtils.hasText(metric.getDescription())) { return metric.getDescription(); } return method.getName(); } else { - ManagedOperation mo = this.attributeSource.getManagedOperation(method); + ManagedOperation mo = obtainAttributeSource().getManagedOperation(method); if (mo != null && StringUtils.hasText(mo.getDescription())) { return mo.getDescription(); } @@ -257,7 +263,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem */ @Override protected MBeanParameterInfo[] getOperationParameters(Method method, String beanKey) { - ManagedOperationParameter[] params = this.attributeSource.getManagedOperationParameters(method); + ManagedOperationParameter[] params = obtainAttributeSource().getManagedOperationParameters(method); if (ObjectUtils.isEmpty(params)) { return super.getOperationParameters(method, beanKey); } @@ -279,7 +285,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem @Override protected ModelMBeanNotificationInfo[] getNotificationInfo(Object managedBean, String beanKey) { ManagedNotification[] notificationAttributes = - this.attributeSource.getManagedNotifications(getClassToExpose(managedBean)); + obtainAttributeSource().getManagedNotifications(getClassToExpose(managedBean)); ModelMBeanNotificationInfo[] notificationInfos = new ModelMBeanNotificationInfo[notificationAttributes.length]; @@ -299,7 +305,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem */ @Override protected void populateMBeanDescriptor(Descriptor desc, Object managedBean, String beanKey) { - ManagedResource mr = this.attributeSource.getManagedResource(getClassToExpose(managedBean)); + ManagedResource mr = obtainAttributeSource().getManagedResource(getClassToExpose(managedBean)); if (mr == null) { throw new InvalidMetadataException( "No ManagedResource attribute found for class: " + getClassToExpose(managedBean)); @@ -337,15 +343,15 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem Descriptor desc, @Nullable Method getter, @Nullable Method setter, String beanKey) { if (getter != null) { - ManagedMetric metric = this.attributeSource.getManagedMetric(getter); + ManagedMetric metric = obtainAttributeSource().getManagedMetric(getter); if (metric != null) { populateMetricDescriptor(desc, metric); return; } } - ManagedAttribute gma = (getter != null ? this.attributeSource.getManagedAttribute(getter) : null); - ManagedAttribute sma = (setter != null ? this.attributeSource.getManagedAttribute(setter) : null); + ManagedAttribute gma = (getter != null ? obtainAttributeSource().getManagedAttribute(getter) : null); + ManagedAttribute sma = (setter != null ? obtainAttributeSource().getManagedAttribute(setter) : null); populateAttributeDescriptor(desc, (gma != null ? gma : ManagedAttribute.EMPTY), (sma != null ? sma : ManagedAttribute.EMPTY)); @@ -399,7 +405,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem */ @Override protected void populateOperationDescriptor(Descriptor desc, Method method, String beanKey) { - ManagedOperation mo = this.attributeSource.getManagedOperation(method); + ManagedOperation mo = obtainAttributeSource().getManagedOperation(method); if (mo != null) { applyCurrencyTimeLimit(desc, mo.getCurrencyTimeLimit()); } diff --git a/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssembler.java b/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssembler.java index d4517c29e1..1c8690efde 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssembler.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssembler.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 java.util.Map; import java.util.Properties; import java.util.Set; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -57,8 +58,10 @@ import org.springframework.util.StringUtils; */ public class MethodExclusionMBeanInfoAssembler extends AbstractConfigurableMBeanInfoAssembler { + @Nullable private Set ignoredMethods; + @Nullable private Map> ignoredMethodMappings; diff --git a/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssembler.java b/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssembler.java index f36ffedfa1..38f6583e78 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssembler.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssembler.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 java.util.Map; import java.util.Properties; import java.util.Set; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -57,11 +58,13 @@ public class MethodNameBasedMBeanInfoAssembler extends AbstractConfigurableMBean /** * Stores the set of method names to use for creating the management interface. */ + @Nullable private Set managedMethods; /** * Stores the mappings of bean keys to an array of method names. */ + @Nullable private Map> methodMappings; diff --git a/spring-context/src/main/java/org/springframework/jmx/export/naming/KeyNamingStrategy.java b/spring-context/src/main/java/org/springframework/jmx/export/naming/KeyNamingStrategy.java index 1a7f34ecbd..cd4efba2e4 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/naming/KeyNamingStrategy.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/naming/KeyNamingStrategy.java @@ -61,6 +61,7 @@ public class KeyNamingStrategy implements ObjectNamingStrategy, InitializingBean /** * Stores the mappings of bean key to {@code ObjectName}. */ + @Nullable private Properties mappings; /** @@ -68,12 +69,14 @@ public class KeyNamingStrategy implements ObjectNamingStrategy, InitializingBean * into the final merged set of {@code Properties} used for {@code ObjectName} * resolution. */ + @Nullable private Resource[] mappingLocations; /** * Stores the result of merging the {@code mappings} {@code Properties} * with the properties stored in the resources defined by {@code mappingLocations}. */ + @Nullable private Properties mergedMappings; diff --git a/spring-context/src/main/java/org/springframework/jmx/export/naming/MetadataNamingStrategy.java b/spring-context/src/main/java/org/springframework/jmx/export/naming/MetadataNamingStrategy.java index 6c9219d5c6..8943a5f2d4 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/naming/MetadataNamingStrategy.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/naming/MetadataNamingStrategy.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.springframework.beans.factory.InitializingBean; import org.springframework.jmx.export.metadata.JmxAttributeSource; import org.springframework.jmx.export.metadata.ManagedResource; import org.springframework.jmx.support.ObjectNameManager; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -51,8 +52,10 @@ public class MetadataNamingStrategy implements ObjectNamingStrategy, Initializin /** * The {@code JmxAttributeSource} implementation to use for reading metadata. */ + @Nullable private JmxAttributeSource attributeSource; + @Nullable private String defaultDomain; @@ -107,7 +110,8 @@ public class MetadataNamingStrategy implements ObjectNamingStrategy, Initializin * with the managed resource's {@code Class}. */ @Override - public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException { + public ObjectName getObjectName(Object managedBean, @Nullable String beanKey) throws MalformedObjectNameException { + Assert.state(this.attributeSource != null, "No JmxAttributeSource set"); Class managedClass = AopUtils.getTargetClass(managedBean); ManagedResource mr = this.attributeSource.getManagedResource(managedClass); @@ -116,6 +120,7 @@ public class MetadataNamingStrategy implements ObjectNamingStrategy, Initializin return ObjectNameManager.getInstance(mr.getObjectName()); } else { + Assert.state(beanKey != null, "No ManagedResource attribute and no bean key specified"); try { return ObjectNameManager.getInstance(beanKey); } diff --git a/spring-context/src/main/java/org/springframework/jmx/support/ConnectorServerFactoryBean.java b/spring-context/src/main/java/org/springframework/jmx/support/ConnectorServerFactoryBean.java index f1b0e0efcc..f26d0ec2d5 100644 --- a/spring-context/src/main/java/org/springframework/jmx/support/ConnectorServerFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/jmx/support/ConnectorServerFactoryBean.java @@ -64,14 +64,17 @@ public class ConnectorServerFactoryBean extends MBeanRegistrationSupport private Map environment = new HashMap<>(); + @Nullable private MBeanServerForwarder forwarder; + @Nullable private ObjectName objectName; private boolean threaded = false; private boolean daemon = false; + @Nullable private JMXConnectorServer connectorServer; @@ -224,11 +227,13 @@ public class ConnectorServerFactoryBean extends MBeanRegistrationSupport */ @Override public void destroy() throws IOException { - if (logger.isInfoEnabled()) { - logger.info("Stopping JMX connector server: " + this.connectorServer); - } try { - this.connectorServer.stop(); + if (this.connectorServer != null) { + if (logger.isInfoEnabled()) { + logger.info("Stopping JMX connector server: " + this.connectorServer); + } + this.connectorServer.stop(); + } } finally { unregisterBeans(); diff --git a/spring-context/src/main/java/org/springframework/jmx/support/MBeanRegistrationSupport.java b/spring-context/src/main/java/org/springframework/jmx/support/MBeanRegistrationSupport.java index d292be0061..1f922cf4a0 100644 --- a/spring-context/src/main/java/org/springframework/jmx/support/MBeanRegistrationSupport.java +++ b/spring-context/src/main/java/org/springframework/jmx/support/MBeanRegistrationSupport.java @@ -28,6 +28,7 @@ import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -75,6 +76,7 @@ public class MBeanRegistrationSupport { /** * The {@code MBeanServer} instance being used to register beans. */ + @Nullable protected MBeanServer server; /** @@ -101,6 +103,7 @@ public class MBeanRegistrationSupport { /** * Return the {@code MBeanServer} that the beans will be registered with. */ + @Nullable public final MBeanServer getServer() { return this.server; } @@ -125,6 +128,7 @@ public class MBeanRegistrationSupport { * @throws JMException if the registration failed */ protected void doRegister(Object mbean, ObjectName objectName) throws JMException { + Assert.state(this.server != null, "No MBeanServer set"); ObjectName actualObjectName; synchronized (this.registeredBeans) { @@ -188,6 +192,7 @@ public class MBeanRegistrationSupport { * @param objectName the suggested ObjectName for the MBean */ protected void doUnregister(ObjectName objectName) { + Assert.state(this.server != null, "No MBeanServer set"); boolean actuallyUnregistered = false; synchronized (this.registeredBeans) { diff --git a/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBean.java b/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBean.java index 67ef26ab92..034085d639 100644 --- a/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBean.java @@ -34,6 +34,7 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -53,18 +54,23 @@ import org.springframework.util.CollectionUtils; public class MBeanServerConnectionFactoryBean implements FactoryBean, BeanClassLoaderAware, InitializingBean, DisposableBean { + @Nullable private JMXServiceURL serviceUrl; private Map environment = new HashMap<>(); private boolean connectOnStartup = true; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private JMXConnector connector; + @Nullable private MBeanServerConnection connection; + @Nullable private JMXConnectorLazyInitTargetSource connectorTargetSource; @@ -131,6 +137,7 @@ public class MBeanServerConnectionFactoryBean * environment properties. */ private void connect() throws IOException { + Assert.state(this.serviceUrl != null, "No JMXServiceURL set"); this.connector = JMXConnectorFactory.connect(this.serviceUrl, this.environment); this.connection = this.connector.getMBeanServerConnection(); } @@ -170,7 +177,8 @@ public class MBeanServerConnectionFactoryBean */ @Override public void destroy() throws IOException { - if (this.connectorTargetSource == null || this.connectorTargetSource.isInitialized()) { + if (this.connector != null && + (this.connectorTargetSource == null || this.connectorTargetSource.isInitialized())) { this.connector.close(); } } @@ -186,6 +194,7 @@ public class MBeanServerConnectionFactoryBean @Override protected Object createObject() throws Exception { + Assert.state(serviceUrl != null, "No JMXServiceURL set"); return JMXConnectorFactory.connect(serviceUrl, environment); } @@ -203,6 +212,7 @@ public class MBeanServerConnectionFactoryBean @Override protected Object createObject() throws Exception { + Assert.state(connector != null, "JMXConnector not initialized"); return connector.getMBeanServerConnection(); } diff --git a/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerFactoryBean.java b/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerFactoryBean.java index 0639aa87d9..b262da33db 100644 --- a/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/jmx/support/MBeanServerFactoryBean.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. @@ -58,12 +58,15 @@ public class MBeanServerFactoryBean implements FactoryBean, Initial private boolean locateExistingServerIfPossible = false; + @Nullable private String agentId; + @Nullable private String defaultDomain; private boolean registerWithFactory = true; + @Nullable private MBeanServer server; private boolean newlyRegistered = false; diff --git a/spring-context/src/main/java/org/springframework/jmx/support/NotificationListenerHolder.java b/spring-context/src/main/java/org/springframework/jmx/support/NotificationListenerHolder.java index 0ab0b385ad..4c3b82806c 100644 --- a/spring-context/src/main/java/org/springframework/jmx/support/NotificationListenerHolder.java +++ b/spring-context/src/main/java/org/springframework/jmx/support/NotificationListenerHolder.java @@ -41,12 +41,16 @@ import org.springframework.util.ObjectUtils; */ public class NotificationListenerHolder { + @Nullable private NotificationListener notificationListener; + @Nullable private NotificationFilter notificationFilter; + @Nullable private Object handback; + @Nullable protected Set mappedObjectNames; diff --git a/spring-context/src/main/java/org/springframework/jmx/support/WebSphereMBeanServerFactoryBean.java b/spring-context/src/main/java/org/springframework/jmx/support/WebSphereMBeanServerFactoryBean.java index 627b5f6335..200bee62bc 100644 --- a/spring-context/src/main/java/org/springframework/jmx/support/WebSphereMBeanServerFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/jmx/support/WebSphereMBeanServerFactoryBean.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. @@ -23,6 +23,7 @@ import javax.management.MBeanServer; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.jmx.MBeanServerNotFoundException; +import org.springframework.lang.Nullable; /** * {@link FactoryBean} that obtains a WebSphere {@link javax.management.MBeanServer} @@ -52,6 +53,7 @@ public class WebSphereMBeanServerFactoryBean implements FactoryBean private static final String GET_MBEAN_SERVER_METHOD = "getMBeanServer"; + @Nullable private MBeanServer mbeanServer; diff --git a/spring-context/src/main/java/org/springframework/jndi/JndiObjectFactoryBean.java b/spring-context/src/main/java/org/springframework/jndi/JndiObjectFactoryBean.java index f710fd0bc0..4ce061a6ba 100644 --- a/spring-context/src/main/java/org/springframework/jndi/JndiObjectFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/jndi/JndiObjectFactoryBean.java @@ -33,6 +33,8 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** @@ -70,6 +72,7 @@ import org.springframework.util.ClassUtils; public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryBean, BeanFactoryAware, BeanClassLoaderAware { + @Nullable private Class[] proxyInterfaces; private boolean lookupOnStartup = true; @@ -78,12 +81,16 @@ public class JndiObjectFactoryBean extends JndiObjectLocator private boolean exposeAccessContext = false; + @Nullable private Object defaultObject; + @Nullable private ConfigurableBeanFactory beanFactory; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private Object jndiObject; @@ -310,7 +317,9 @@ public class JndiObjectFactoryBean extends JndiObjectLocator // Create a JndiObjectTargetSource that mirrors the JndiObjectFactoryBean's configuration. JndiObjectTargetSource targetSource = new JndiObjectTargetSource(); targetSource.setJndiTemplate(jof.getJndiTemplate()); - targetSource.setJndiName(jof.getJndiName()); + String jndiName = jof.getJndiName(); + Assert.state(jndiName != null, "No JNDI name specified"); + targetSource.setJndiName(jndiName); targetSource.setExpectedType(jof.getExpectedType()); targetSource.setResourceRef(jof.isResourceRef()); targetSource.setLookupOnStartup(jof.lookupOnStartup); diff --git a/spring-context/src/main/java/org/springframework/jndi/JndiObjectLocator.java b/spring-context/src/main/java/org/springframework/jndi/JndiObjectLocator.java index 63f9e6c4d2..969c207377 100644 --- a/spring-context/src/main/java/org/springframework/jndi/JndiObjectLocator.java +++ b/spring-context/src/main/java/org/springframework/jndi/JndiObjectLocator.java @@ -20,6 +20,7 @@ import javax.naming.NamingException; import org.springframework.beans.factory.InitializingBean; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -48,8 +49,10 @@ import org.springframework.util.StringUtils; */ public abstract class JndiObjectLocator extends JndiLocatorSupport implements InitializingBean { + @Nullable private String jndiName; + @Nullable private Class expectedType; @@ -66,6 +69,7 @@ public abstract class JndiObjectLocator extends JndiLocatorSupport implements In /** * Return the JNDI name to look up. */ + @Nullable public String getJndiName() { return this.jndiName; } @@ -105,7 +109,9 @@ public abstract class JndiObjectLocator extends JndiLocatorSupport implements In * @see #lookup(String, Class) */ protected Object lookup() throws NamingException { - return lookup(getJndiName(), getExpectedType()); + String jndiName = getJndiName(); + Assert.state(jndiName != null, "No JNDI name specified"); + return lookup(jndiName, getExpectedType()); } } diff --git a/spring-context/src/main/java/org/springframework/jndi/JndiObjectTargetSource.java b/spring-context/src/main/java/org/springframework/jndi/JndiObjectTargetSource.java index 5e28a1b728..146306c5e5 100644 --- a/spring-context/src/main/java/org/springframework/jndi/JndiObjectTargetSource.java +++ b/spring-context/src/main/java/org/springframework/jndi/JndiObjectTargetSource.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. @@ -19,6 +19,7 @@ package org.springframework.jndi; import javax.naming.NamingException; import org.springframework.aop.TargetSource; +import org.springframework.lang.Nullable; /** * AOP {@link org.springframework.aop.TargetSource} that provides @@ -64,8 +65,10 @@ public class JndiObjectTargetSource extends JndiObjectLocator implements TargetS private boolean cache = true; + @Nullable private Object cachedObject; + @Nullable private Class targetClass; diff --git a/spring-context/src/main/java/org/springframework/jndi/JndiTemplate.java b/spring-context/src/main/java/org/springframework/jndi/JndiTemplate.java index 3186518833..26a4b7c31b 100644 --- a/spring-context/src/main/java/org/springframework/jndi/JndiTemplate.java +++ b/spring-context/src/main/java/org/springframework/jndi/JndiTemplate.java @@ -43,6 +43,7 @@ public class JndiTemplate { protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private Properties environment; diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AbstractAsyncConfiguration.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AbstractAsyncConfiguration.java index 887fb6b690..b79e3947a6 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AbstractAsyncConfiguration.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AbstractAsyncConfiguration.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. @@ -25,6 +25,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportAware; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; /** @@ -39,10 +40,13 @@ import org.springframework.util.CollectionUtils; @Configuration public abstract class AbstractAsyncConfiguration implements ImportAware { + @Nullable protected AnnotationAttributes enableAsync; + @Nullable protected Executor executor; + @Nullable protected AsyncUncaughtExceptionHandler exceptionHandler; diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java index 8cad245841..f04efd853e 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java @@ -152,7 +152,6 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B * @param asyncAnnotationTypes the async annotation types to introspect * @return the applicable Pointcut object, or {@code null} if none */ - @Nullable protected Pointcut buildPointcut(Set> asyncAnnotationTypes) { ComposablePointcut result = null; for (Class asyncAnnotationType : asyncAnnotationTypes) { @@ -166,7 +165,7 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B } result = result.union(mpc); } - return result; + return (result != null ? result : Pointcut.TRUE); } } diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java index 6d699b3961..3b2446507b 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.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. @@ -26,6 +26,7 @@ import org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvis import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.beans.factory.BeanFactory; import org.springframework.core.task.TaskExecutor; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -74,10 +75,13 @@ public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAd protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private Class asyncAnnotationType; + @Nullable private Executor executor; + @Nullable private AsyncUncaughtExceptionHandler exceptionHandler; diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java index ed299c19fb..9f297c57a3 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java @@ -47,8 +47,10 @@ import org.springframework.util.concurrent.SuccessCallback; */ public class AsyncResult implements ListenableFuture { + @Nullable private final V value; + @Nullable private final Throwable executionException; @@ -86,6 +88,7 @@ public class AsyncResult implements ListenableFuture { } @Override + @Nullable public V get() throws ExecutionException { if (this.executionException != null) { throw (this.executionException instanceof ExecutionException ? @@ -96,6 +99,7 @@ public class AsyncResult implements ListenableFuture { } @Override + @Nullable public V get(long timeout, TimeUnit unit) throws ExecutionException { return get(); } diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java index 8fcfb298f6..cf2347c724 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java @@ -53,6 +53,7 @@ import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.MethodIntrospector; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.lang.Nullable; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.config.CronTask; @@ -107,14 +108,19 @@ public class ScheduledAnnotationBeanPostProcessor protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private Object scheduler; + @Nullable private StringValueResolver embeddedValueResolver; + @Nullable private String beanName; + @Nullable private BeanFactory beanFactory; + @Nullable private ApplicationContext applicationContext; private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar(); @@ -216,12 +222,12 @@ public class ScheduledAnnotationBeanPostProcessor Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type"); try { // Search for TaskScheduler bean... - this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, false)); + this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, false)); } catch (NoUniqueBeanDefinitionException ex) { logger.debug("Could not find unique TaskScheduler bean", ex); try { - this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, true)); + this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, true)); } catch (NoSuchBeanDefinitionException ex2) { if (logger.isInfoEnabled()) { @@ -237,12 +243,12 @@ public class ScheduledAnnotationBeanPostProcessor logger.debug("Could not find default TaskScheduler bean", ex); // Search for ScheduledExecutorService bean next... try { - this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, false)); + this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, false)); } catch (NoUniqueBeanDefinitionException ex2) { logger.debug("Could not find unique ScheduledExecutorService bean", ex2); try { - this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, true)); + this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, true)); } catch (NoSuchBeanDefinitionException ex3) { if (logger.isInfoEnabled()) { @@ -265,25 +271,24 @@ public class ScheduledAnnotationBeanPostProcessor this.registrar.afterPropertiesSet(); } - private T resolveSchedulerBean(Class schedulerType, boolean byName) { + private T resolveSchedulerBean(BeanFactory beanFactory, Class schedulerType, boolean byName) { if (byName) { - T scheduler = this.beanFactory.getBean(DEFAULT_TASK_SCHEDULER_BEAN_NAME, schedulerType); - if (this.beanFactory instanceof ConfigurableBeanFactory) { + T scheduler = beanFactory.getBean(DEFAULT_TASK_SCHEDULER_BEAN_NAME, schedulerType); + if (this.beanName != null && this.beanFactory instanceof ConfigurableBeanFactory) { ((ConfigurableBeanFactory) this.beanFactory).registerDependentBean( DEFAULT_TASK_SCHEDULER_BEAN_NAME, this.beanName); } return scheduler; } - else if (this.beanFactory instanceof AutowireCapableBeanFactory) { - NamedBeanHolder holder = ((AutowireCapableBeanFactory) this.beanFactory).resolveNamedBean(schedulerType); - if (this.beanFactory instanceof ConfigurableBeanFactory) { - ((ConfigurableBeanFactory) this.beanFactory).registerDependentBean( - holder.getBeanName(), this.beanName); + else if (beanFactory instanceof AutowireCapableBeanFactory) { + NamedBeanHolder holder = ((AutowireCapableBeanFactory) beanFactory).resolveNamedBean(schedulerType); + if (this.beanName != null && beanFactory instanceof ConfigurableBeanFactory) { + ((ConfigurableBeanFactory) beanFactory).registerDependentBean(holder.getBeanName(), this.beanName); } return holder.getBeanInstance(); } else { - return this.beanFactory.getBean(schedulerType); + return beanFactory.getBean(schedulerType); } } diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java index 9e5ec49de4..a662e01814 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java @@ -63,6 +63,7 @@ import org.springframework.util.concurrent.ListenableFuture; */ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, SchedulingTaskExecutor { + @Nullable private static Class managedExecutorServiceClass; static { diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java index 39bb4a6e97..1c9c55c542 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java @@ -65,6 +65,7 @@ import org.springframework.util.ErrorHandler; */ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements TaskScheduler { + @Nullable private static Class managedScheduledExecutorServiceClass; static { @@ -79,10 +80,12 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T } } + private ScheduledExecutorService scheduledExecutor; private boolean enterpriseConcurrentScheduler = false; + @Nullable private ErrorHandler errorHandler; @@ -93,7 +96,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T */ public ConcurrentTaskScheduler() { super(); - setScheduledExecutor(null); + this.scheduledExecutor = initScheduledExecutor(null); } /** @@ -108,7 +111,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T */ public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) { super(scheduledExecutor); - setScheduledExecutor(scheduledExecutor); + this.scheduledExecutor = initScheduledExecutor(scheduledExecutor); } /** @@ -124,10 +127,23 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T */ public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) { super(concurrentExecutor); - setScheduledExecutor(scheduledExecutor); + this.scheduledExecutor = initScheduledExecutor(scheduledExecutor); } + private ScheduledExecutorService initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) { + if (scheduledExecutor != null) { + this.scheduledExecutor = scheduledExecutor; + this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClass != null && + managedScheduledExecutorServiceClass.isInstance(scheduledExecutor)); + } + else { + this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); + this.enterpriseConcurrentScheduler = false; + } + return this.scheduledExecutor; + } + /** * Specify the {@link java.util.concurrent.ScheduledExecutorService} to delegate to. *

Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService} @@ -139,16 +155,8 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T * as well, pass the same executor reference to {@link #setConcurrentExecutor}. * @see #setConcurrentExecutor */ - public final void setScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) { - if (scheduledExecutor != null) { - this.scheduledExecutor = scheduledExecutor; - this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClass != null && - managedScheduledExecutorServiceClass.isInstance(scheduledExecutor)); - } - else { - this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); - this.enterpriseConcurrentScheduler = false; - } + public void setScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) { + initScheduledExecutor(scheduledExecutor); } /** @@ -167,7 +175,8 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T return new EnterpriseConcurrentTriggerScheduler().schedule(decorateTask(task, true), trigger); } else { - ErrorHandler errorHandler = (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true)); + ErrorHandler errorHandler = + (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true)); return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule(); } } diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedAwareThreadFactory.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedAwareThreadFactory.java index 9f67ab1b7d..755a5c13e2 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedAwareThreadFactory.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedAwareThreadFactory.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. @@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.jndi.JndiLocatorDelegate; import org.springframework.jndi.JndiTemplate; +import org.springframework.lang.Nullable; /** * JNDI-based variant of {@link CustomizableThreadFactory}, performing a default lookup @@ -51,8 +52,10 @@ public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory private JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); + @Nullable private String jndiName = "java:comp/DefaultManagedThreadFactory"; + @Nullable private ThreadFactory threadFactory; diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskExecutor.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskExecutor.java index 803491d104..b830acb86f 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskExecutor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskExecutor.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,6 +23,7 @@ import javax.naming.NamingException; import org.springframework.beans.factory.InitializingBean; import org.springframework.jndi.JndiLocatorDelegate; import org.springframework.jndi.JndiTemplate; +import org.springframework.lang.Nullable; /** * JNDI-based variant of {@link ConcurrentTaskExecutor}, performing a default lookup for @@ -40,6 +41,7 @@ public class DefaultManagedTaskExecutor extends ConcurrentTaskExecutor implement private JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); + @Nullable private String jndiName = "java:comp/DefaultManagedExecutorService"; diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.java index 989c4370f7..80787576d0 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/DefaultManagedTaskScheduler.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,6 +23,7 @@ import javax.naming.NamingException; import org.springframework.beans.factory.InitializingBean; import org.springframework.jndi.JndiLocatorDelegate; import org.springframework.jndi.JndiTemplate; +import org.springframework.lang.Nullable; /** * JNDI-based variant of {@link ConcurrentTaskScheduler}, performing a default lookup for @@ -40,6 +41,7 @@ public class DefaultManagedTaskScheduler extends ConcurrentTaskScheduler impleme private JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); + @Nullable private String jndiName = "java:comp/DefaultManagedScheduledExecutorService"; diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java index e29173fc9f..039353e645 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java @@ -58,8 +58,10 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac private int awaitTerminationSeconds = 0; + @Nullable private String beanName; + @Nullable private ExecutorService executor; @@ -82,7 +84,7 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac } @Override - public void setThreadNamePrefix(String threadNamePrefix) { + public void setThreadNamePrefix(@Nullable String threadNamePrefix) { super.setThreadNamePrefix(threadNamePrefix); this.threadNamePrefixSet = true; } @@ -197,29 +199,30 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac * Perform a shutdown on the underlying ExecutorService. * @see java.util.concurrent.ExecutorService#shutdown() * @see java.util.concurrent.ExecutorService#shutdownNow() - * @see #awaitTerminationIfNecessary() */ public void shutdown() { if (logger.isInfoEnabled()) { logger.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : "")); } - if (this.waitForTasksToCompleteOnShutdown) { - this.executor.shutdown(); + if (this.executor != null) { + if (this.waitForTasksToCompleteOnShutdown) { + this.executor.shutdown(); + } + else { + this.executor.shutdownNow(); + } + awaitTerminationIfNecessary(this.executor); } - else { - this.executor.shutdownNow(); - } - awaitTerminationIfNecessary(); } /** * Wait for the executor to terminate, according to the value of the * {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"} property. */ - private void awaitTerminationIfNecessary() { + private void awaitTerminationIfNecessary(ExecutorService executor) { if (this.awaitTerminationSeconds > 0) { try { - if (!this.executor.awaitTermination(this.awaitTerminationSeconds, TimeUnit.SECONDS)) { + if (!executor.awaitTermination(this.awaitTerminationSeconds, TimeUnit.SECONDS)) { if (logger.isWarnEnabled()) { logger.warn("Timed out while waiting for executor" + (this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate"); diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.java index b43d04ecbe..6c5bbec09d 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.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. @@ -28,6 +28,7 @@ import org.springframework.lang.Nullable; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable; import org.springframework.scheduling.support.SimpleTriggerContext; +import org.springframework.util.Assert; import org.springframework.util.ErrorHandler; /** @@ -50,14 +51,18 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc private final ScheduledExecutorService executor; + @Nullable private ScheduledFuture currentFuture; + @Nullable private Date scheduledExecutionTime; private final Object triggerContextMonitor = new Object(); - public ReschedulingRunnable(Runnable delegate, Trigger trigger, ScheduledExecutorService executor, ErrorHandler errorHandler) { + public ReschedulingRunnable( + Runnable delegate, Trigger trigger, ScheduledExecutorService executor, ErrorHandler errorHandler) { + super(delegate, errorHandler); this.trigger = trigger; this.executor = executor; @@ -77,14 +82,20 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc } } + private ScheduledFuture obtainCurrentFuture() { + Assert.state(this.currentFuture != null, "No scheduled future"); + return this.currentFuture; + } + @Override public void run() { Date actualExecutionTime = new Date(); super.run(); Date completionTime = new Date(); synchronized (this.triggerContextMonitor) { + Assert.state(this.scheduledExecutionTime != null, "No scheduled execution"); this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime); - if (!this.currentFuture.isCancelled()) { + if (!obtainCurrentFuture().isCancelled()) { schedule(); } } @@ -94,21 +105,21 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc @Override public boolean cancel(boolean mayInterruptIfRunning) { synchronized (this.triggerContextMonitor) { - return this.currentFuture.cancel(mayInterruptIfRunning); + return obtainCurrentFuture().cancel(mayInterruptIfRunning); } } @Override public boolean isCancelled() { synchronized (this.triggerContextMonitor) { - return this.currentFuture.isCancelled(); + return obtainCurrentFuture().isCancelled(); } } @Override public boolean isDone() { synchronized (this.triggerContextMonitor) { - return this.currentFuture.isDone(); + return obtainCurrentFuture().isDone(); } } @@ -116,7 +127,7 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc public Object get() throws InterruptedException, ExecutionException { ScheduledFuture curr; synchronized (this.triggerContextMonitor) { - curr = this.currentFuture; + curr = obtainCurrentFuture(); } return curr.get(); } @@ -125,7 +136,7 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { ScheduledFuture curr; synchronized (this.triggerContextMonitor) { - curr = this.currentFuture; + curr = obtainCurrentFuture(); } return curr.get(timeout, unit); } @@ -134,7 +145,7 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc public long getDelay(TimeUnit unit) { ScheduledFuture curr; synchronized (this.triggerContextMonitor) { - curr = this.currentFuture; + curr = obtainCurrentFuture(); } return curr.getDelay(unit); } diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBean.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBean.java index 739bdbcb73..3bc0469204 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBean.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.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable; import org.springframework.scheduling.support.TaskUtils; import org.springframework.util.Assert; @@ -75,6 +76,7 @@ public class ScheduledExecutorFactoryBean extends ExecutorConfigurationSupport private int poolSize = 1; + @Nullable private ScheduledExecutorTask[] scheduledExecutorTasks; private boolean removeOnCancelPolicy = false; @@ -83,6 +85,7 @@ public class ScheduledExecutorFactoryBean extends ExecutorConfigurationSupport private boolean exposeUnconfigurableExecutor = false; + @Nullable private ScheduledExecutorService exposedExecutor; diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java index 2125223fef..561e3e7e21 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.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. @@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * JavaBean that allows for configuring a {@link java.util.concurrent.ThreadPoolExecutor} @@ -68,6 +69,7 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport private boolean exposeUnconfigurableExecutor = false; + @Nullable private ExecutorService exposedExecutor; diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java index b7180c69b2..4837b68d90 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.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. @@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.core.task.AsyncListenableTaskExecutor; import org.springframework.core.task.TaskDecorator; import org.springframework.core.task.TaskRejectedException; +import org.springframework.lang.Nullable; import org.springframework.scheduling.SchedulingTaskExecutor; import org.springframework.util.Assert; import org.springframework.util.concurrent.ListenableFuture; @@ -83,8 +84,10 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport private boolean allowCoreThreadTimeOut = false; + @Nullable private TaskDecorator taskDecorator; + @Nullable private ThreadPoolExecutor threadPoolExecutor; diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java index 7fa4f4fc4e..2c098b2761 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java @@ -61,10 +61,12 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport private volatile boolean removeOnCancelPolicy = false; - private volatile ScheduledExecutorService scheduledExecutor; - + @Nullable private volatile ErrorHandler errorHandler; + @Nullable + private ScheduledExecutorService scheduledExecutor; + /** * Set the ScheduledExecutorService's pool size. @@ -236,8 +238,9 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport ExecutorService executor = getScheduledExecutor(); try { Callable taskToUse = task; - if (this.errorHandler != null) { - taskToUse = new DelegatingErrorHandlingCallable<>(task, this.errorHandler); + ErrorHandler errorHandler = this.errorHandler; + if (errorHandler != null) { + taskToUse = new DelegatingErrorHandlingCallable<>(task, errorHandler); } return executor.submit(taskToUse); } @@ -284,8 +287,10 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport public ScheduledFuture schedule(Runnable task, Trigger trigger) { ScheduledExecutorService executor = getScheduledExecutor(); try { - ErrorHandler errorHandler = - (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true)); + ErrorHandler errorHandler = this.errorHandler; + if (errorHandler == null) { + errorHandler = TaskUtils.getDefaultErrorHandler(true); + } return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule(); } catch (RejectedExecutionException ex) { diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTask.java b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTask.java index dffdb3e2ca..45e87ad282 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTask.java +++ b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTask.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,8 @@ package org.springframework.scheduling.config; import java.util.concurrent.ScheduledFuture; +import org.springframework.lang.Nullable; + /** * A representation of a scheduled task, * used as a return value for scheduling methods. @@ -29,6 +31,7 @@ import java.util.concurrent.ScheduledFuture; */ public final class ScheduledTask { + @Nullable volatile ScheduledFuture future; diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java index 8c19d64545..0d96748920 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java +++ b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java @@ -56,16 +56,22 @@ import org.springframework.util.CollectionUtils; */ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean { + @Nullable private TaskScheduler taskScheduler; + @Nullable private ScheduledExecutorService localExecutor; + @Nullable private List triggerTasks; + @Nullable private List cronTasks; + @Nullable private List fixedRateTasks; + @Nullable private List fixedDelayTasks; private final Map unresolvedTasks = new HashMap<>(16); diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/TaskExecutorFactoryBean.java b/spring-context/src/main/java/org/springframework/scheduling/config/TaskExecutorFactoryBean.java index 7ed6bef329..9a9420ce6c 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/config/TaskExecutorFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/scheduling/config/TaskExecutorFactoryBean.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,6 +23,7 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.task.TaskExecutor; +import org.springframework.lang.Nullable; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.StringUtils; @@ -37,16 +38,22 @@ import org.springframework.util.StringUtils; public class TaskExecutorFactoryBean implements FactoryBean, BeanNameAware, InitializingBean, DisposableBean { + @Nullable private String poolSize; + @Nullable private Integer queueCapacity; + @Nullable private RejectedExecutionHandler rejectedExecutionHandler; + @Nullable private Integer keepAliveSeconds; + @Nullable private String beanName; + @Nullable private ThreadPoolTaskExecutor target; @@ -74,24 +81,25 @@ public class TaskExecutorFactoryBean implements @Override public void afterPropertiesSet() { - this.target = new ThreadPoolTaskExecutor(); - determinePoolSizeRange(); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + determinePoolSizeRange(executor); if (this.queueCapacity != null) { - this.target.setQueueCapacity(this.queueCapacity); + executor.setQueueCapacity(this.queueCapacity); } if (this.keepAliveSeconds != null) { - this.target.setKeepAliveSeconds(this.keepAliveSeconds); + executor.setKeepAliveSeconds(this.keepAliveSeconds); } if (this.rejectedExecutionHandler != null) { - this.target.setRejectedExecutionHandler(this.rejectedExecutionHandler); + executor.setRejectedExecutionHandler(this.rejectedExecutionHandler); } if (this.beanName != null) { - this.target.setThreadNamePrefix(this.beanName + "-"); + executor.setThreadNamePrefix(this.beanName + "-"); } - this.target.afterPropertiesSet(); + executor.afterPropertiesSet(); + this.target = executor; } - private void determinePoolSizeRange() { + private void determinePoolSizeRange(ThreadPoolTaskExecutor executor) { if (StringUtils.hasText(this.poolSize)) { try { int corePoolSize; @@ -109,7 +117,7 @@ public class TaskExecutorFactoryBean implements if (corePoolSize == 0) { // Actually set 'corePoolSize' to the upper bound of the range // but allow core threads to timeout... - this.target.setAllowCoreThreadTimeOut(true); + executor.setAllowCoreThreadTimeOut(true); corePoolSize = maxPoolSize; } else { @@ -124,8 +132,8 @@ public class TaskExecutorFactoryBean implements corePoolSize = value; maxPoolSize = value; } - this.target.setCorePoolSize(corePoolSize); - this.target.setMaxPoolSize(maxPoolSize); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); } catch (NumberFormatException ex) { throw new IllegalArgumentException("Invalid pool-size value [" + this.poolSize + "]: only single " + @@ -153,7 +161,9 @@ public class TaskExecutorFactoryBean implements @Override public void destroy() { - this.target.destroy(); + if (this.target != null) { + this.target.destroy(); + } } } diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/MethodInvokingRunnable.java b/spring-context/src/main/java/org/springframework/scheduling/support/MethodInvokingRunnable.java index 495e46099e..24d2353387 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/support/MethodInvokingRunnable.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/MethodInvokingRunnable.java @@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.support.ArgumentConvertingMethodInvoker; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -42,6 +43,7 @@ public class MethodInvokingRunnable extends ArgumentConvertingMethodInvoker protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); diff --git a/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptFactory.java b/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptFactory.java index 5f400544b1..074edfa43d 100644 --- a/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptFactory.java +++ b/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptFactory.java @@ -47,10 +47,13 @@ public class BshScriptFactory implements ScriptFactory, BeanClassLoaderAware { private final String scriptSourceLocator; + @Nullable private final Class[] scriptInterfaces; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private Class scriptClass; private final Object scriptClassMonitor = new Object(); @@ -101,6 +104,7 @@ public class BshScriptFactory implements ScriptFactory, BeanClassLoaderAware { } @Override + @Nullable public Class[] getScriptInterfaces() { return this.scriptInterfaces; } diff --git a/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptUtils.java b/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptUtils.java index 9fbda73055..b5a59ef64f 100644 --- a/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptUtils.java +++ b/spring-context/src/main/java/org/springframework/scripting/bsh/BshScriptUtils.java @@ -116,10 +116,12 @@ public abstract class BshScriptUtils { * @throws EvalError in case of BeanShell parsing failure */ @Nullable - static Class determineBshObjectType(String scriptSource, ClassLoader classLoader) throws EvalError { + static Class determineBshObjectType(String scriptSource, @Nullable ClassLoader classLoader) throws EvalError { Assert.hasText(scriptSource, "Script source must not be empty"); Interpreter interpreter = new Interpreter(); - interpreter.setClassLoader(classLoader); + if (classLoader != null) { + interpreter.setClassLoader(classLoader); + } Object result = interpreter.eval(scriptSource); if (result instanceof Class) { return (Class) result; diff --git a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java index 8de452cce5..ce05cf6081 100644 --- a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java +++ b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java @@ -41,6 +41,7 @@ import org.springframework.scripting.support.ResourceScriptSource; */ public class GroovyScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware { + @Nullable private ClassLoader classLoader; private CompilerConfiguration compilerConfiguration = new CompilerConfiguration(); diff --git a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java index b4e8fa3ab7..68b82eddae 100644 --- a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java +++ b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java @@ -61,16 +61,22 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea private final String scriptSourceLocator; + @Nullable private GroovyObjectCustomizer groovyObjectCustomizer; + @Nullable private CompilerConfiguration compilerConfiguration; + @Nullable private GroovyClassLoader groovyClassLoader; + @Nullable private Class scriptClass; + @Nullable private Class scriptResultClass; + @Nullable private CachedResultHolder cachedResult; private final Object scriptClassMonitor = new Object(); @@ -348,6 +354,7 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea */ private static class CachedResultHolder { + @Nullable public final Object object; public CachedResultHolder(@Nullable Object object) { diff --git a/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java b/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java index ec05663a5b..88c22ad6a6 100644 --- a/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scripting/support/ScriptFactoryPostProcessor.java @@ -56,6 +56,7 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.lang.Nullable; import org.springframework.scripting.ScriptFactory; import org.springframework.scripting.ScriptSource; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -161,6 +162,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces private static final String SCRIPTED_OBJECT_NAME_PREFIX = "scriptedObject."; + /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); @@ -168,8 +170,10 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces private boolean defaultProxyTargetClass = false; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private ConfigurableBeanFactory beanFactory; private ResourceLoader resourceLoader = new DefaultResourceLoader(); @@ -179,6 +183,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces /** Map from bean name String to ScriptSource object */ private final Map scriptSourceCache = new HashMap<>(); + /** * Set the delay between refresh checks, in milliseconds. * Default is -1, indicating no refresh checks at all. @@ -228,7 +233,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces } @Override - public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { + public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @@ -237,6 +242,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces return Integer.MIN_VALUE; } + @Override public Class predictBeanType(Class beanClass, String beanName) { // We only apply special treatment to ScriptFactory implementations here. @@ -244,6 +250,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces return null; } + Assert.state(this.beanFactory != null, "No BeanFactory set"); BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName); try { @@ -293,6 +300,7 @@ public class ScriptFactoryPostProcessor extends InstantiationAwareBeanPostProces return null; } + Assert.state(this.beanFactory != null, "No BeanFactory set"); BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName); String scriptFactoryBeanName = SCRIPT_FACTORY_NAME_PREFIX + beanName; String scriptedObjectBeanName = SCRIPTED_OBJECT_NAME_PREFIX + beanName; diff --git a/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptEvaluator.java b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptEvaluator.java index 71516562e2..e792a1aeb7 100644 --- a/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptEvaluator.java +++ b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptEvaluator.java @@ -43,10 +43,15 @@ import org.springframework.util.StringUtils; */ public class StandardScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware { - private volatile ScriptEngineManager scriptEngineManager; - + @Nullable private String engineName; + @Nullable + private volatile Bindings globalBindings; + + @Nullable + private volatile ScriptEngineManager scriptEngineManager; + /** * Construct a new {@code StandardScriptEvaluator}. @@ -102,16 +107,25 @@ public class StandardScriptEvaluator implements ScriptEvaluator, BeanClassLoader * @see javax.script.ScriptEngineManager#setBindings(Bindings) * @see javax.script.SimpleBindings */ - public void setGlobalBindings(@Nullable Map globalBindings) { - if (globalBindings != null) { - this.scriptEngineManager.setBindings(StandardScriptUtils.getBindings(globalBindings)); + public void setGlobalBindings(Map globalBindings) { + Bindings bindings = StandardScriptUtils.getBindings(globalBindings); + this.globalBindings = bindings; + ScriptEngineManager scriptEngineManager = this.scriptEngineManager; + if (scriptEngineManager != null) { + scriptEngineManager.setBindings(bindings); } } @Override public void setBeanClassLoader(ClassLoader classLoader) { - if (this.scriptEngineManager == null) { - this.scriptEngineManager = new ScriptEngineManager(classLoader); + ScriptEngineManager scriptEngineManager = this.scriptEngineManager; + if (scriptEngineManager == null) { + scriptEngineManager = new ScriptEngineManager(classLoader); + this.scriptEngineManager = scriptEngineManager; + Bindings bindings = this.globalBindings; + if (bindings != null) { + scriptEngineManager.setBindings(bindings); + } } } @@ -147,12 +161,14 @@ public class StandardScriptEvaluator implements ScriptEvaluator, BeanClassLoader * @return the ScriptEngine (never {@code null}) */ protected ScriptEngine getScriptEngine(ScriptSource script) { - if (this.scriptEngineManager == null) { - this.scriptEngineManager = new ScriptEngineManager(); + ScriptEngineManager scriptEngineManager = this.scriptEngineManager; + if (scriptEngineManager == null) { + scriptEngineManager = new ScriptEngineManager(); + this.scriptEngineManager = scriptEngineManager; } if (StringUtils.hasText(this.engineName)) { - return StandardScriptUtils.retrieveEngineByName(this.scriptEngineManager, this.engineName); + return StandardScriptUtils.retrieveEngineByName(scriptEngineManager, this.engineName); } else if (script instanceof ResourceScriptSource) { Resource resource = ((ResourceScriptSource) script).getResource(); @@ -161,7 +177,7 @@ public class StandardScriptEvaluator implements ScriptEvaluator, BeanClassLoader throw new IllegalStateException( "No script language defined, and no file extension defined for resource: " + resource); } - ScriptEngine engine = this.scriptEngineManager.getEngineByExtension(extension); + ScriptEngine engine = scriptEngineManager.getEngineByExtension(extension); if (engine == null) { throw new IllegalStateException("No matching engine found for file extension '" + extension + "'"); } diff --git a/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java index 046c70b6dc..0c48b931cc 100644 --- a/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java +++ b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java @@ -48,14 +48,18 @@ import org.springframework.util.StringUtils; */ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAware { + @Nullable private final String scriptEngineName; private final String scriptSourceLocator; + @Nullable private final Class[] scriptInterfaces; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private volatile ScriptEngine scriptEngine; @@ -120,6 +124,7 @@ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAwar } @Override + @Nullable public Class[] getScriptInterfaces() { return this.scriptInterfaces; } @@ -180,13 +185,15 @@ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAwar protected Object evaluateScript(ScriptSource scriptSource) { try { - if (this.scriptEngine == null) { - this.scriptEngine = retrieveScriptEngine(scriptSource); - if (this.scriptEngine == null) { + ScriptEngine scriptEngine = this.scriptEngine; + if (scriptEngine == null) { + scriptEngine = retrieveScriptEngine(scriptSource); + if (scriptEngine == null) { throw new IllegalStateException("Could not determine script engine for " + scriptSource); } + this.scriptEngine = scriptEngine; } - return this.scriptEngine.eval(scriptSource.getScriptAsString()); + return scriptEngine.eval(scriptSource.getScriptAsString()); } catch (Exception ex) { throw new ScriptCompilationException(scriptSource, ex); @@ -218,7 +225,9 @@ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAwar } @Nullable - protected Object adaptToInterfaces(@Nullable Object script, ScriptSource scriptSource, Class... actualInterfaces) { + protected Object adaptToInterfaces( + @Nullable Object script, ScriptSource scriptSource, Class... actualInterfaces) { + Class adaptedIfc; if (actualInterfaces.length == 1) { adaptedIfc = actualInterfaces[0]; @@ -228,12 +237,12 @@ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAwar } if (adaptedIfc != null) { - if (!(this.scriptEngine instanceof Invocable)) { + ScriptEngine scriptEngine = this.scriptEngine; + if (!(scriptEngine instanceof Invocable)) { throw new ScriptCompilationException(scriptSource, - "ScriptEngine must implement Invocable in order to adapt it to an interface: " + - this.scriptEngine); + "ScriptEngine must implement Invocable in order to adapt it to an interface: " + scriptEngine); } - Invocable invocable = (Invocable) this.scriptEngine; + Invocable invocable = (Invocable) scriptEngine; if (script != null) { script = invocable.getInterface(script, adaptedIfc); } diff --git a/spring-context/src/main/java/org/springframework/scripting/support/StaticScriptSource.java b/spring-context/src/main/java/org/springframework/scripting/support/StaticScriptSource.java index 8e2673da2a..839c65aad1 100644 --- a/spring-context/src/main/java/org/springframework/scripting/support/StaticScriptSource.java +++ b/spring-context/src/main/java/org/springframework/scripting/support/StaticScriptSource.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,10 +32,11 @@ import org.springframework.util.Assert; */ public class StaticScriptSource implements ScriptSource { - private String script; + private String script = ""; private boolean modified; + @Nullable private String className; diff --git a/spring-context/src/main/java/org/springframework/ui/context/support/DelegatingThemeSource.java b/spring-context/src/main/java/org/springframework/ui/context/support/DelegatingThemeSource.java index fcd9fbe06c..a222d11a0a 100644 --- a/spring-context/src/main/java/org/springframework/ui/context/support/DelegatingThemeSource.java +++ b/spring-context/src/main/java/org/springframework/ui/context/support/DelegatingThemeSource.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. @@ -34,6 +34,7 @@ import org.springframework.ui.context.ThemeSource; */ public class DelegatingThemeSource implements HierarchicalThemeSource { + @Nullable private ThemeSource parentThemeSource; @@ -43,6 +44,7 @@ public class DelegatingThemeSource implements HierarchicalThemeSource { } @Override + @Nullable public ThemeSource getParentThemeSource() { return parentThemeSource; } diff --git a/spring-context/src/main/java/org/springframework/ui/context/support/ResourceBundleThemeSource.java b/spring-context/src/main/java/org/springframework/ui/context/support/ResourceBundleThemeSource.java index b2890564e3..80d1d7cb02 100644 --- a/spring-context/src/main/java/org/springframework/ui/context/support/ResourceBundleThemeSource.java +++ b/spring-context/src/main/java/org/springframework/ui/context/support/ResourceBundleThemeSource.java @@ -47,14 +47,18 @@ public class ResourceBundleThemeSource implements HierarchicalThemeSource, BeanC protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private ThemeSource parentThemeSource; private String basenamePrefix = ""; + @Nullable private String defaultEncoding; + @Nullable private Boolean fallbackToSystemLocale; + @Nullable private ClassLoader beanClassLoader; /** Map from theme name to Theme instance */ @@ -75,6 +79,7 @@ public class ResourceBundleThemeSource implements HierarchicalThemeSource, BeanC } @Override + @Nullable public ThemeSource getParentThemeSource() { return this.parentThemeSource; } diff --git a/spring-context/src/main/java/org/springframework/validation/AbstractPropertyBindingResult.java b/spring-context/src/main/java/org/springframework/validation/AbstractPropertyBindingResult.java index efbb08d9c3..ecedb35fe2 100644 --- a/spring-context/src/main/java/org/springframework/validation/AbstractPropertyBindingResult.java +++ b/spring-context/src/main/java/org/springframework/validation/AbstractPropertyBindingResult.java @@ -43,6 +43,7 @@ import org.springframework.util.Assert; @SuppressWarnings("serial") public abstract class AbstractPropertyBindingResult extends AbstractBindingResult { + @Nullable private transient ConversionService conversionService; diff --git a/spring-context/src/main/java/org/springframework/validation/BeanPropertyBindingResult.java b/spring-context/src/main/java/org/springframework/validation/BeanPropertyBindingResult.java index a5f9939ef9..a9264f693f 100644 --- a/spring-context/src/main/java/org/springframework/validation/BeanPropertyBindingResult.java +++ b/spring-context/src/main/java/org/springframework/validation/BeanPropertyBindingResult.java @@ -44,12 +44,14 @@ import org.springframework.util.Assert; @SuppressWarnings("serial") public class BeanPropertyBindingResult extends AbstractPropertyBindingResult implements Serializable { + @Nullable private final Object target; private final boolean autoGrowNestedPaths; private final int autoGrowCollectionLimit; + @Nullable private transient BeanWrapper beanWrapper; @@ -80,6 +82,7 @@ public class BeanPropertyBindingResult extends AbstractPropertyBindingResult imp @Override + @Nullable public final Object getTarget() { return this.target; } diff --git a/spring-context/src/main/java/org/springframework/validation/DataBinder.java b/spring-context/src/main/java/org/springframework/validation/DataBinder.java index 960ce20e35..bfe212230a 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -120,12 +120,15 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { */ protected static final Log logger = LogFactory.getLog(DataBinder.class); + @Nullable private final Object target; private final String objectName; + @Nullable private AbstractPropertyBindingResult bindingResult; + @Nullable private SimpleTypeConverter typeConverter; private boolean ignoreUnknownFields = true; @@ -136,14 +139,19 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { private int autoGrowCollectionLimit = DEFAULT_AUTO_GROW_COLLECTION_LIMIT; + @Nullable private String[] allowedFields; + @Nullable private String[] disallowedFields; + @Nullable private String[] requiredFields; + @Nullable private ConversionService conversionService; + @Nullable private MessageCodesResolver messageCodesResolver; private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor(); @@ -167,7 +175,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * if the binder is just used to convert a plain parameter value) * @param objectName the name of the target object */ - public DataBinder(@Nullable Object target, @Nullable String objectName) { + public DataBinder(@Nullable Object target, String objectName) { this.target = ObjectUtils.unwrapOptional(target); this.objectName = objectName; } @@ -424,6 +432,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * Return the fields that should be allowed for binding. * @return array of field names */ + @Nullable public String[] getAllowedFields() { return this.allowedFields; } @@ -447,6 +456,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * Return the fields that should not be allowed for binding. * @return array of field names */ + @Nullable public String[] getDisallowedFields() { return this.disallowedFields; } @@ -473,6 +483,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * Return the fields that are required for each binding process. * @return array of field names */ + @Nullable public String[] getRequiredFields() { return this.requiredFields; } diff --git a/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java b/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java index b8df6ff42f..dc49142e0a 100644 --- a/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java +++ b/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java @@ -37,10 +37,12 @@ import org.springframework.util.Assert; @SuppressWarnings("serial") public class DirectFieldBindingResult extends AbstractPropertyBindingResult { + @Nullable private final Object target; private final boolean autoGrowNestedPaths; + @Nullable private transient ConfigurablePropertyAccessor directFieldAccessor; @@ -67,6 +69,7 @@ public class DirectFieldBindingResult extends AbstractPropertyBindingResult { @Override + @Nullable public final Object getTarget() { return this.target; } diff --git a/spring-context/src/main/java/org/springframework/validation/FieldError.java b/spring-context/src/main/java/org/springframework/validation/FieldError.java index 377f6c73c2..1f498448b9 100644 --- a/spring-context/src/main/java/org/springframework/validation/FieldError.java +++ b/spring-context/src/main/java/org/springframework/validation/FieldError.java @@ -37,6 +37,7 @@ public class FieldError extends ObjectError { private final String field; + @Nullable private final Object rejectedValue; private final boolean bindingFailure; @@ -84,6 +85,7 @@ public class FieldError extends ObjectError { /** * Return the rejected field value. */ + @Nullable public Object getRejectedValue() { return this.rejectedValue; } diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.java index bac3469b82..1c7a8a9d54 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.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. @@ -27,6 +27,8 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Simple {@link BeanPostProcessor} that checks JSR-303 constraint annotations @@ -38,6 +40,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor; */ public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean { + @Nullable private Validator validator; private boolean afterInitialization = false; @@ -103,6 +106,7 @@ public class BeanValidationPostProcessor implements BeanPostProcessor, Initializ * @see javax.validation.Validator#validate */ protected void doValidate(Object bean) { + Assert.state(this.validator != null, "No Validator set"); Set> result = this.validator.validate(bean); if (!result.isEmpty()) { StringBuilder sb = new StringBuilder("Bean state is invalid: "); diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java index bf7d220795..c930b3c42e 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.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. @@ -24,6 +24,7 @@ import javax.validation.ValidatorContext; import javax.validation.ValidatorFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * Configurable bean class that exposes a specific JSR-303 Validator @@ -35,10 +36,13 @@ import org.springframework.beans.factory.InitializingBean; */ public class CustomValidatorBean extends SpringValidatorAdapter implements Validator, InitializingBean { + @Nullable private ValidatorFactory validatorFactory; + @Nullable private MessageInterpolator messageInterpolator; + @Nullable private TraversableResolver traversableResolver; diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java index 7ed2ca0e45..004f167c28 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java @@ -87,24 +87,33 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean { @SuppressWarnings("rawtypes") + @Nullable private Class providerClass; + @Nullable private ValidationProviderResolver validationProviderResolver; + @Nullable private MessageInterpolator messageInterpolator; + @Nullable private TraversableResolver traversableResolver; + @Nullable private ConstraintValidatorFactory constraintValidatorFactory; + @Nullable private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); + @Nullable private Resource[] mappingLocations; private final Map validationPropertyMap = new HashMap<>(); + @Nullable private ApplicationContext applicationContext; + @Nullable private ValidatorFactory validatorFactory; @@ -273,7 +282,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter } if (this.parameterNameDiscoverer != null) { - configureParameterNameProviderIfPossible(configuration); + configureParameterNameProvider(this.parameterNameDiscoverer, configuration); } if (this.mappingLocations != null) { @@ -296,8 +305,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter setTargetValidator(this.validatorFactory.getValidator()); } - private void configureParameterNameProviderIfPossible(Configuration configuration) { - final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer; + private void configureParameterNameProvider(ParameterNameDiscoverer discoverer, Configuration configuration) { final ParameterNameProvider defaultProvider = configuration.getDefaultParameterNameProvider(); configuration.parameterNameProvider(new ParameterNameProvider() { @Override @@ -386,16 +394,19 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter // ignore - we'll try ValidatorFactory unwrapping next } } - try { - return this.validatorFactory.unwrap(type); - } - catch (ValidationException ex) { - // ignore if just being asked for ValidatorFactory - if (ValidatorFactory.class == type) { - return (T) this.validatorFactory; + if (this.validatorFactory != null) { + try { + return this.validatorFactory.unwrap(type); + } + catch (ValidationException ex) { + // ignore if just being asked for ValidatorFactory + if (ValidatorFactory.class == type) { + return (T) this.validatorFactory; + } + throw ex; } - throw ex; } + throw new ValidationException("Cannot unwrap to " + type); } public void close() { diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java index 8a28f4c9d2..7840edb841 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java @@ -65,6 +65,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. internalAnnotationAttributes.add("payload"); } + @Nullable private javax.validation.Validator targetValidator; @@ -316,6 +317,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. @Override public ExecutableValidator forExecutables() { + Assert.state(this.targetValidator != null, "No target Validator set"); return this.targetValidator.forExecutables(); } diff --git a/spring-core/src/main/java/org/springframework/core/ConfigurableObjectInputStream.java b/spring-core/src/main/java/org/springframework/core/ConfigurableObjectInputStream.java index 4b4943d8cc..b542254810 100644 --- a/spring-core/src/main/java/org/springframework/core/ConfigurableObjectInputStream.java +++ b/spring-core/src/main/java/org/springframework/core/ConfigurableObjectInputStream.java @@ -35,6 +35,7 @@ import org.springframework.util.ClassUtils; */ public class ConfigurableObjectInputStream extends ObjectInputStream { + @Nullable private final ClassLoader classLoader; private final boolean acceptProxyClasses; diff --git a/spring-core/src/main/java/org/springframework/core/MethodClassKey.java b/spring-core/src/main/java/org/springframework/core/MethodClassKey.java index bbe735a8d1..23f2dd7b10 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodClassKey.java +++ b/spring-core/src/main/java/org/springframework/core/MethodClassKey.java @@ -33,6 +33,7 @@ public final class MethodClassKey implements Comparable { private final Method method; + @Nullable private final Class targetClass; diff --git a/spring-core/src/main/java/org/springframework/core/MethodParameter.java b/spring-core/src/main/java/org/springframework/core/MethodParameter.java index 582cb071ca..07ea4252c0 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -63,31 +63,38 @@ public class MethodParameter { ClassUtils.isPresent("kotlin.Unit", MethodParameter.class.getClassLoader()); - private final Method method; - - private final Constructor constructor; + private final Executable executable; private final int parameterIndex; + @Nullable private volatile Parameter parameter; private int nestingLevel = 1; /** Map from Integer level to Integer type index */ + @Nullable Map typeIndexesPerLevel; + @Nullable private volatile Class containingClass; + @Nullable private volatile Class parameterType; + @Nullable private volatile Type genericParameterType; + @Nullable private volatile Annotation[] parameterAnnotations; + @Nullable private volatile ParameterNameDiscoverer parameterNameDiscoverer; + @Nullable private volatile String parameterName; + @Nullable private volatile MethodParameter nestedMethodParameter; @@ -114,10 +121,9 @@ public class MethodParameter { */ public MethodParameter(Method method, int parameterIndex, int nestingLevel) { Assert.notNull(method, "Method must not be null"); - this.method = method; + this.executable = method; this.parameterIndex = validateIndex(method, parameterIndex); this.nestingLevel = nestingLevel; - this.constructor = null; } /** @@ -139,10 +145,9 @@ public class MethodParameter { */ public MethodParameter(Constructor constructor, int parameterIndex, int nestingLevel) { Assert.notNull(constructor, "Constructor must not be null"); - this.constructor = constructor; + this.executable = constructor; this.parameterIndex = validateIndex(constructor, parameterIndex); this.nestingLevel = nestingLevel; - this.method = null; } /** @@ -152,8 +157,7 @@ public class MethodParameter { */ public MethodParameter(MethodParameter original) { Assert.notNull(original, "Original must not be null"); - this.method = original.method; - this.constructor = original.constructor; + this.executable = original.executable; this.parameterIndex = original.parameterIndex; this.parameter = original.parameter; this.nestingLevel = original.nestingLevel; @@ -174,7 +178,7 @@ public class MethodParameter { */ @Nullable public Method getMethod() { - return this.method; + return (this.executable instanceof Method ? (Method) this.executable : null); } /** @@ -184,14 +188,14 @@ public class MethodParameter { */ @Nullable public Constructor getConstructor() { - return this.constructor; + return (this.executable instanceof Constructor ? (Constructor) this.executable : null); } /** * Return the class that declares the underlying Method or Constructor. */ public Class getDeclaringClass() { - return getMember().getDeclaringClass(); + return this.executable.getDeclaringClass(); } /** @@ -199,7 +203,7 @@ public class MethodParameter { * @return the Method or Constructor as Member */ public Member getMember() { - return getExecutable(); + return this.executable; } /** @@ -209,7 +213,7 @@ public class MethodParameter { * @return the Method or Constructor as AnnotatedElement */ public AnnotatedElement getAnnotatedElement() { - return getExecutable(); + return this.executable; } /** @@ -218,7 +222,7 @@ public class MethodParameter { * @since 5.0 */ public Executable getExecutable() { - return (this.method != null ? this.method : this.constructor); + return this.executable; } /** @@ -226,10 +230,12 @@ public class MethodParameter { * @since 5.0 */ public Parameter getParameter() { - if (this.parameter == null) { - this.parameter = getExecutable().getParameters()[this.parameterIndex]; + Parameter parameter = this.parameter; + if (parameter == null) { + parameter = getExecutable().getParameters()[this.parameterIndex]; + this.parameter = parameter; } - return this.parameter; + return parameter; } /** @@ -316,10 +322,11 @@ public class MethodParameter { * @since 4.3 */ public MethodParameter nested() { - if (this.nestedMethodParameter != null) { - return this.nestedMethodParameter; + MethodParameter nestedParam = this.nestedMethodParameter; + if (nestedParam != null) { + return nestedParam; } - MethodParameter nestedParam = clone(); + nestedParam = clone(); nestedParam.nestingLevel = this.nestingLevel + 1; this.nestedMethodParameter = nestedParam; return nestedParam; @@ -372,7 +379,8 @@ public class MethodParameter { } public Class getContainingClass() { - return (this.containingClass != null ? this.containingClass : getDeclaringClass()); + Class containingClass = this.containingClass; + return (containingClass != null ? containingClass : getDeclaringClass()); } /** @@ -387,17 +395,18 @@ public class MethodParameter { * @return the parameter type (never {@code null}) */ public Class getParameterType() { - if (this.parameterType == null) { + Class paramType = this.parameterType; + if (paramType == null) { if (this.parameterIndex < 0) { - this.parameterType = (this.method != null ? this.method.getReturnType() : null); + Method method = getMethod(); + paramType = (method != null ? method.getReturnType() : void.class); } else { - this.parameterType = (this.method != null ? - this.method.getParameterTypes()[this.parameterIndex] : - this.constructor.getParameterTypes()[this.parameterIndex]); + paramType = this.executable.getParameterTypes()[this.parameterIndex]; } + this.parameterType = paramType; } - return this.parameterType; + return paramType; } /** @@ -406,17 +415,18 @@ public class MethodParameter { * @since 3.0 */ public Type getGenericParameterType() { - if (this.genericParameterType == null) { + Type paramType = this.genericParameterType; + if (paramType == null) { if (this.parameterIndex < 0) { - this.genericParameterType = (this.method != null ? this.method.getGenericReturnType() : void.class); + Method method = getMethod(); + paramType = (method != null ? method.getGenericReturnType() : void.class); } else { - this.genericParameterType = (this.method != null ? - this.method.getGenericParameterTypes()[this.parameterIndex] : - this.constructor.getGenericParameterTypes()[this.parameterIndex]); + paramType = this.executable.getGenericParameterTypes()[this.parameterIndex]; } + this.genericParameterType = paramType; } - return this.genericParameterType; + return paramType; } /** @@ -507,17 +517,18 @@ public class MethodParameter { * Return the annotations associated with the specific method/constructor parameter. */ public Annotation[] getParameterAnnotations() { - if (this.parameterAnnotations == null) { - Annotation[][] annotationArray = (this.method != null ? - this.method.getParameterAnnotations() : this.constructor.getParameterAnnotations()); + Annotation[] paramAnns = this.parameterAnnotations; + if (paramAnns == null) { + Annotation[][] annotationArray = this.executable.getParameterAnnotations(); if (this.parameterIndex >= 0 && this.parameterIndex < annotationArray.length) { - this.parameterAnnotations = adaptAnnotationArray(annotationArray[this.parameterIndex]); + paramAnns = adaptAnnotationArray(annotationArray[this.parameterIndex]); } else { - this.parameterAnnotations = new Annotation[0]; + paramAnns = new Annotation[0]; } + this.parameterAnnotations = paramAnns; } - return this.parameterAnnotations; + return paramAnns; } /** @@ -576,8 +587,13 @@ public class MethodParameter { public String getParameterName() { ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer; if (discoverer != null) { - String[] parameterNames = (this.method != null ? - discoverer.getParameterNames(this.method) : discoverer.getParameterNames(this.constructor)); + String[] parameterNames = null; + if (this.executable instanceof Method) { + parameterNames = discoverer.getParameterNames((Method) this.executable); + } + else if (this.executable instanceof Constructor) { + parameterNames = discoverer.getParameterNames((Constructor) this.executable); + } if (parameterNames != null) { this.parameterName = parameterNames[this.parameterIndex]; } @@ -626,12 +642,13 @@ public class MethodParameter { @Override public int hashCode() { - return (getMember().hashCode() * 31 + this.parameterIndex); + return (getExecutable().hashCode() * 31 + this.parameterIndex); } @Override public String toString() { - return (this.method != null ? "method '" + this.method.getName() + "'" : "constructor") + + Method method = getMethod(); + return (method != null ? "method '" + method.getName() + "'" : "constructor") + " parameter " + this.parameterIndex; } diff --git a/spring-core/src/main/java/org/springframework/core/OverridingClassLoader.java b/spring-core/src/main/java/org/springframework/core/OverridingClassLoader.java index 6331c37e81..19d88a207e 100644 --- a/spring-core/src/main/java/org/springframework/core/OverridingClassLoader.java +++ b/spring-core/src/main/java/org/springframework/core/OverridingClassLoader.java @@ -47,6 +47,7 @@ public class OverridingClassLoader extends DecoratingClassLoader { } + @Nullable private final ClassLoader overrideDelegate; diff --git a/spring-core/src/main/java/org/springframework/core/ReactiveTypeDescriptor.java b/spring-core/src/main/java/org/springframework/core/ReactiveTypeDescriptor.java index a1c2551594..cf2deab161 100644 --- a/spring-core/src/main/java/org/springframework/core/ReactiveTypeDescriptor.java +++ b/spring-core/src/main/java/org/springframework/core/ReactiveTypeDescriptor.java @@ -32,12 +32,11 @@ public class ReactiveTypeDescriptor { private final Class reactiveType; + @Nullable private final Supplier emptyValueSupplier; private final boolean multiValue; - private final boolean supportsEmpty; - private final boolean noValue; @@ -45,14 +44,12 @@ public class ReactiveTypeDescriptor { * Private constructor. See static factory methods. */ private ReactiveTypeDescriptor(Class reactiveType, @Nullable Supplier emptySupplier, - boolean multiValue, boolean canBeEmpty, boolean noValue) { + boolean multiValue, boolean noValue) { Assert.notNull(reactiveType, "'reactiveType' must not be null"); - Assert.isTrue(!canBeEmpty || emptySupplier != null, "Empty value supplier is required."); this.reactiveType = reactiveType; this.emptyValueSupplier = emptySupplier; this.multiValue = multiValue; - this.supportsEmpty = canBeEmpty; this.noValue = noValue; } @@ -69,7 +66,7 @@ public class ReactiveTypeDescriptor { * Use of this type implies {@link #supportsEmpty()} is true. */ public Object getEmptyValue() { - Assert.isTrue(supportsEmpty(), "Empty values not supported."); + Assert.state(this.emptyValueSupplier != null, "Empty values not supported"); return this.emptyValueSupplier.get(); } @@ -87,7 +84,7 @@ public class ReactiveTypeDescriptor { * Return {@code true} if the reactive type can complete with no values. */ public boolean supportsEmpty() { - return this.supportsEmpty; + return (this.emptyValueSupplier != null); } /** @@ -122,7 +119,7 @@ public class ReactiveTypeDescriptor { * @param emptySupplier a supplier of an empty-value instance of the reactive type */ public static ReactiveTypeDescriptor multiValue(Class type, Supplier emptySupplier) { - return new ReactiveTypeDescriptor(type, emptySupplier, true, true, false); + return new ReactiveTypeDescriptor(type, emptySupplier, true, false); } /** @@ -131,7 +128,7 @@ public class ReactiveTypeDescriptor { * @param emptySupplier a supplier of an empty-value instance of the reactive type */ public static ReactiveTypeDescriptor singleOptionalValue(Class type, Supplier emptySupplier) { - return new ReactiveTypeDescriptor(type, emptySupplier, false, true, false); + return new ReactiveTypeDescriptor(type, emptySupplier, false, false); } /** @@ -139,7 +136,7 @@ public class ReactiveTypeDescriptor { * @param type the reactive type */ public static ReactiveTypeDescriptor singleRequiredValue(Class type) { - return new ReactiveTypeDescriptor(type, null, false, false, false); + return new ReactiveTypeDescriptor(type, null, false, false); } /** @@ -148,7 +145,7 @@ public class ReactiveTypeDescriptor { * @param emptySupplier a supplier of an empty-value instance of the reactive type */ public static ReactiveTypeDescriptor noValue(Class type, Supplier emptySupplier) { - return new ReactiveTypeDescriptor(type, emptySupplier, false, true, true); + return new ReactiveTypeDescriptor(type, emptySupplier, false, true); } } 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 2201b8ffb6..f9fabf2c80 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -102,29 +102,37 @@ public class ResolvableType implements Serializable { /** * Optional provider for the type. */ + @Nullable private final TypeProvider typeProvider; /** * The {@code VariableResolver} to use or {@code null} if no resolver is available. */ + @Nullable private final VariableResolver variableResolver; /** * The component type for an array or {@code null} if the type should be deduced. */ + @Nullable private final ResolvableType componentType; /** * Copy of the resolved value. */ + @Nullable private final Class resolved; + @Nullable private final Integer hash; + @Nullable private ResolvableType superType; + @Nullable private ResolvableType[] interfaces; + @Nullable private ResolvableType[] generics; @@ -147,7 +155,7 @@ public class ResolvableType implements Serializable { * @since 4.2 */ private ResolvableType(Type type, @Nullable TypeProvider typeProvider, - @Nullable VariableResolver variableResolver, Integer hash) { + @Nullable VariableResolver variableResolver, @Nullable Integer hash) { this.type = type; this.typeProvider = typeProvider; @@ -1131,7 +1139,7 @@ public class ResolvableType implements Serializable { * @return a {@link ResolvableType} for the specified field * @see #forField(Field) */ - public static ResolvableType forField(Field field, int nestingLevel, Class implementationClass) { + public static ResolvableType forField(Field field, int nestingLevel, @Nullable Class implementationClass) { Assert.notNull(field, "Field must not be null"); ResolvableType owner = forType(implementationClass).as(field.getDeclaringClass()); return forType(null, new FieldTypeProvider(field), owner.asVariableResolver()).getNested(nestingLevel); 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 82b87c085b..9cd318b0bb 100644 --- a/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java +++ b/spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java @@ -296,6 +296,7 @@ abstract class SerializableTypeWrapper { @SuppressWarnings("serial") static class MethodParameterTypeProvider implements TypeProvider { + @Nullable private final String methodName; private final Class[] parameterTypes; @@ -359,6 +360,7 @@ abstract class SerializableTypeWrapper { private transient Method method; + @Nullable private transient volatile Object result; public MethodInvokeTypeProvider(TypeProvider provider, Method method, int index) { @@ -388,14 +390,15 @@ abstract class SerializableTypeWrapper { private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); - this.method = ReflectionUtils.findMethod(this.declaringClass, this.methodName); - if (this.method == null) { + Method method = ReflectionUtils.findMethod(this.declaringClass, this.methodName); + if (method == null) { throw new IllegalStateException("Cannot find method on deserialization: " + this.methodName); } - if (this.method.getReturnType() != Type.class && this.method.getReturnType() != Type[].class) { + if (method.getReturnType() != Type.class && method.getReturnType() != Type[].class) { throw new IllegalStateException( - "Invalid return type on deserialized method - needs to be Type or Type[]: " + this.method); + "Invalid return type on deserialized method - needs to be Type or Type[]: " + method); } + this.method = method; } } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AbstractAliasAwareAnnotationAttributeExtractor.java b/spring-core/src/main/java/org/springframework/core/annotation/AbstractAliasAwareAnnotationAttributeExtractor.java index 22186602b6..d7a7ed3561 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AbstractAliasAwareAnnotationAttributeExtractor.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AbstractAliasAwareAnnotationAttributeExtractor.java @@ -41,6 +41,7 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor implements Anno private final Class annotationType; + @Nullable private final Object annotatedElement; private final S source; @@ -73,6 +74,7 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor implements Anno } @Override + @Nullable public final Object getAnnotatedElement() { return this.annotatedElement; } 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 bfec3091c5..e4e81c3a19 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 @@ -101,6 +101,7 @@ public class AnnotatedElementUtils { /** * {@code null} constant used to denote that the search algorithm should continue. */ + @Nullable private static final Boolean CONTINUE = null; private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; @@ -1425,8 +1426,8 @@ public class AnnotatedElementUtils { *

If this method returns {@code true}, then {@link #getAggregatedResults()} * must return a non-null value. * @return {@code true} if this processor supports aggregated results - * @see #getAggregatedResults * @since 4.3 + * @see #getAggregatedResults */ boolean aggregates(); @@ -1437,10 +1438,9 @@ public class AnnotatedElementUtils { * responsible for asking this processor if it {@link #aggregates} results * and then adding the post-processed results to the list returned by this * method. - * @return the list of results aggregated by this processor - * (never {@code null} unless {@link #aggregates} returns {@code false}) - * @see #aggregates + * @return the list of results aggregated by this processor (never {@code null}) * @since 4.3 + * @see #aggregates */ List getAggregatedResults(); } @@ -1537,7 +1537,7 @@ public class AnnotatedElementUtils { this.classValuesAsString = classValuesAsString; this.nestedAnnotationsAsMap = nestedAnnotationsAsMap; this.aggregates = aggregates; - this.aggregatedResults = (aggregates ? new ArrayList<>() : null); + this.aggregatedResults = (aggregates ? new ArrayList<>() : Collections.emptyList()); } @Override diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java index 6f0d25aaee..9fc70e72a8 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java @@ -48,6 +48,7 @@ public class AnnotationAttributes extends LinkedHashMap { private static final String UNKNOWN = "unknown"; + @Nullable private final Class annotationType; final String displayName; 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 4d2d33279d..063d77678f 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 @@ -136,6 +136,7 @@ public abstract class AnnotationUtils { private static final Map aliasDescriptorCache = new ConcurrentReferenceHashMap<>(256); + @Nullable private static transient Log logger; @@ -1920,6 +1921,7 @@ public abstract class AnnotationUtils { private final Class annotationType; + @Nullable private final Class containerAnnotationType; private final boolean declaredMode; diff --git a/spring-core/src/main/java/org/springframework/core/annotation/OrderUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/OrderUtils.java index 1d575aee80..e0ad41074a 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/OrderUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/OrderUtils.java @@ -34,7 +34,8 @@ import org.springframework.util.ClassUtils; @SuppressWarnings("unchecked") public abstract class OrderUtils { - private static Class priorityAnnotationType = null; + @Nullable + private static Class priorityAnnotationType; static { try { @@ -43,6 +44,7 @@ public abstract class OrderUtils { } catch (Throwable ex) { // javax.annotation.Priority not available, or present but not loadable (on JDK 6) + priorityAnnotationType = null; } } diff --git a/spring-core/src/main/java/org/springframework/core/convert/ConversionFailedException.java b/spring-core/src/main/java/org/springframework/core/convert/ConversionFailedException.java index 9e6bc6b8e2..124f983d4a 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/ConversionFailedException.java +++ b/spring-core/src/main/java/org/springframework/core/convert/ConversionFailedException.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. @@ -29,10 +29,12 @@ import org.springframework.util.ObjectUtils; @SuppressWarnings("serial") public class ConversionFailedException extends ConversionException { + @Nullable private final TypeDescriptor sourceType; private final TypeDescriptor targetType; + @Nullable private final Object value; @@ -57,6 +59,7 @@ public class ConversionFailedException extends ConversionException { /** * Return the source type we tried to convert the value from. */ + @Nullable public TypeDescriptor getSourceType() { return this.sourceType; } @@ -71,6 +74,7 @@ public class ConversionFailedException extends ConversionException { /** * Return the offending value. */ + @Nullable public Object getValue() { return this.value; } diff --git a/spring-core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java b/spring-core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java index 6915a63407..0d71ca5b16 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java +++ b/spring-core/src/main/java/org/springframework/core/convert/ConverterNotFoundException.java @@ -29,6 +29,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ConverterNotFoundException extends ConversionException { + @Nullable private final TypeDescriptor sourceType; private final TypeDescriptor targetType; diff --git a/spring-core/src/main/java/org/springframework/core/convert/Property.java b/spring-core/src/main/java/org/springframework/core/convert/Property.java index c7eb43af22..dac0ee6eb1 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/Property.java +++ b/spring-core/src/main/java/org/springframework/core/convert/Property.java @@ -52,14 +52,17 @@ public final class Property { private final Class objectType; + @Nullable private final Method readMethod; + @Nullable private final Method writeMethod; private final String name; private final MethodParameter methodParameter; + @Nullable private Annotation[] annotations; @@ -147,7 +150,7 @@ public final class Property { } return StringUtils.uncapitalize(this.readMethod.getName().substring(index)); } - else { + else if (this.writeMethod != null) { int index = this.writeMethod.getName().indexOf("set"); if (index == -1) { throw new IllegalArgumentException("Not a setter method"); @@ -155,6 +158,9 @@ public final class Property { index += 3; return StringUtils.uncapitalize(this.writeMethod.getName().substring(index)); } + else { + throw new IllegalStateException("Property is neither readable nor writeable"); + } } private MethodParameter resolveMethodParameter() { diff --git a/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java index 164b672472..3444685e0b 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java +++ b/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java @@ -733,6 +733,7 @@ public class TypeDescriptor implements Serializable { */ private class AnnotatedElementAdapter implements AnnotatedElement, Serializable { + @Nullable private final Annotation[] annotations; public AnnotatedElementAdapter(@Nullable Annotation[] annotations) { diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java b/spring-core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java index 621a7f91f5..101f99b44a 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.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,6 +23,7 @@ import java.util.UUID; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.ConverterRegistry; +import org.springframework.lang.Nullable; /** * A specialization of {@link GenericConversionService} configured by default @@ -39,6 +40,7 @@ import org.springframework.core.convert.converter.ConverterRegistry; */ public class DefaultConversionService extends GenericConversionService { + @Nullable private static volatile DefaultConversionService sharedInstance; @@ -54,14 +56,17 @@ public class DefaultConversionService extends GenericConversionService { * @since 4.3.5 */ public static ConversionService getSharedInstance() { - if (sharedInstance == null) { + DefaultConversionService cs = sharedInstance; + if (cs == null) { synchronized (DefaultConversionService.class) { - if (sharedInstance == null) { - sharedInstance = new DefaultConversionService(); + cs = sharedInstance; + if (cs == null) { + cs = new DefaultConversionService(); + sharedInstance = cs; } } } - return sharedInstance; + return cs; } diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java b/spring-core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java index f98b40356a..28b4fbd1dc 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java @@ -132,8 +132,10 @@ final class MapToMapConverter implements ConditionalGenericConverter { private static class MapEntry { + @Nullable private final Object key; + @Nullable private final Object value; public MapEntry(@Nullable Object key, @Nullable Object value) { diff --git a/spring-core/src/main/java/org/springframework/core/env/AbstractPropertyResolver.java b/spring-core/src/main/java/org/springframework/core/env/AbstractPropertyResolver.java index 09dd7c5b21..e590887625 100644 --- a/spring-core/src/main/java/org/springframework/core/env/AbstractPropertyResolver.java +++ b/spring-core/src/main/java/org/springframework/core/env/AbstractPropertyResolver.java @@ -42,10 +42,13 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private volatile ConfigurableConversionService conversionService; + @Nullable private PropertyPlaceholderHelper nonStrictHelper; + @Nullable private PropertyPlaceholderHelper strictHelper; private boolean ignoreUnresolvableNestedPlaceholders = false; @@ -54,6 +57,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX; + @Nullable private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR; private final Set requiredProperties = new LinkedHashSet<>(); @@ -63,14 +67,17 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe public ConfigurableConversionService getConversionService() { // Need to provide an independent DefaultConversionService, not the // shared DefaultConversionService used by PropertySourcesPropertyResolver. - if (this.conversionService == null) { + ConfigurableConversionService cs = this.conversionService; + if (cs == null) { synchronized (this) { - if (this.conversionService == null) { - this.conversionService = new DefaultConversionService(); + cs = this.conversionService; + if (cs == null) { + cs = new DefaultConversionService(); + this.conversionService = cs; } } } - return conversionService; + return cs; } @Override diff --git a/spring-core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java b/spring-core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java index 424ea518d0..7a1bc16e7d 100644 --- a/spring-core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java +++ b/spring-core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java @@ -31,6 +31,7 @@ import org.springframework.lang.Nullable; */ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver { + @Nullable private final PropertySources propertySources; diff --git a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java index 0496c84bd7..2e6be9ddd4 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.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. @@ -45,8 +45,10 @@ public class ClassPathResource extends AbstractFileResolvingResource { private final String path; + @Nullable private ClassLoader classLoader; + @Nullable private Class clazz; @@ -121,6 +123,7 @@ public class ClassPathResource extends AbstractFileResolvingResource { /** * Return the ClassLoader that this resource will be obtained from. */ + @Nullable public final ClassLoader getClassLoader() { return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader); } diff --git a/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java b/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java index d474390f6e..4b9febb05f 100644 --- a/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java +++ b/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java @@ -46,6 +46,7 @@ import org.springframework.util.StringUtils; */ public class DefaultResourceLoader implements ResourceLoader { + @Nullable private ClassLoader classLoader; private final Set protocolResolvers = new LinkedHashSet<>(4); diff --git a/spring-core/src/main/java/org/springframework/core/io/ResourceEditor.java b/spring-core/src/main/java/org/springframework/core/io/ResourceEditor.java index fcab98d354..ab1d620b02 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ResourceEditor.java +++ b/spring-core/src/main/java/org/springframework/core/io/ResourceEditor.java @@ -51,6 +51,7 @@ public class ResourceEditor extends PropertyEditorSupport { private final ResourceLoader resourceLoader; + @Nullable private PropertyResolver propertyResolver; private final boolean ignoreUnresolvablePlaceholders; diff --git a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java index 65654010d0..a4c38d223f 100644 --- a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java @@ -45,6 +45,7 @@ public class UrlResource extends AbstractFileResolvingResource { /** * Original URI, if available; used for URI and File access. */ + @Nullable private final URI uri; /** diff --git a/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java b/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java index ee9dac08c2..813167abd3 100644 --- a/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java +++ b/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java @@ -47,10 +47,10 @@ public abstract class VfsUtils { private static final String VFS3_PKG = "org.jboss.vfs."; private static final String VFS_NAME = "VFS"; - private static Method VFS_METHOD_GET_ROOT_URL = null; - private static Method VFS_METHOD_GET_ROOT_URI = null; + private static Method VFS_METHOD_GET_ROOT_URL; + private static Method VFS_METHOD_GET_ROOT_URI; - private static Method VIRTUAL_FILE_METHOD_EXISTS = null; + private static Method VIRTUAL_FILE_METHOD_EXISTS; private static Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM; private static Method VIRTUAL_FILE_METHOD_GET_SIZE; private static Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED; @@ -63,35 +63,35 @@ public abstract class VfsUtils { protected static Class VIRTUAL_FILE_VISITOR_INTERFACE; protected static Method VIRTUAL_FILE_METHOD_VISIT; - private static Field VISITOR_ATTRIBUTES_FIELD_RECURSE = null; - private static Method GET_PHYSICAL_FILE = null; + private static Field VISITOR_ATTRIBUTES_FIELD_RECURSE; + private static Method GET_PHYSICAL_FILE; static { ClassLoader loader = VfsUtils.class.getClassLoader(); try { Class vfsClass = loader.loadClass(VFS3_PKG + VFS_NAME); - VFS_METHOD_GET_ROOT_URL = ReflectionUtils.findMethod(vfsClass, "getChild", URL.class); - VFS_METHOD_GET_ROOT_URI = ReflectionUtils.findMethod(vfsClass, "getChild", URI.class); + VFS_METHOD_GET_ROOT_URL = vfsClass.getMethod("getChild", URL.class); + VFS_METHOD_GET_ROOT_URI = vfsClass.getMethod("getChild", URI.class); Class virtualFile = loader.loadClass(VFS3_PKG + "VirtualFile"); - VIRTUAL_FILE_METHOD_EXISTS = ReflectionUtils.findMethod(virtualFile, "exists"); - VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = ReflectionUtils.findMethod(virtualFile, "openStream"); - VIRTUAL_FILE_METHOD_GET_SIZE = ReflectionUtils.findMethod(virtualFile, "getSize"); - VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = ReflectionUtils.findMethod(virtualFile, "getLastModified"); - VIRTUAL_FILE_METHOD_TO_URI = ReflectionUtils.findMethod(virtualFile, "toURI"); - VIRTUAL_FILE_METHOD_TO_URL = ReflectionUtils.findMethod(virtualFile, "toURL"); - VIRTUAL_FILE_METHOD_GET_NAME = ReflectionUtils.findMethod(virtualFile, "getName"); - VIRTUAL_FILE_METHOD_GET_PATH_NAME = ReflectionUtils.findMethod(virtualFile, "getPathName"); - GET_PHYSICAL_FILE = ReflectionUtils.findMethod(virtualFile, "getPhysicalFile"); - VIRTUAL_FILE_METHOD_GET_CHILD = ReflectionUtils.findMethod(virtualFile, "getChild", String.class); + VIRTUAL_FILE_METHOD_EXISTS = virtualFile.getMethod("exists"); + VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = virtualFile.getMethod("openStream"); + VIRTUAL_FILE_METHOD_GET_SIZE = virtualFile.getMethod("getSize"); + VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = virtualFile.getMethod("getLastModified"); + VIRTUAL_FILE_METHOD_TO_URI = virtualFile.getMethod("toURI"); + VIRTUAL_FILE_METHOD_TO_URL = virtualFile.getMethod("toURL"); + VIRTUAL_FILE_METHOD_GET_NAME = virtualFile.getMethod("getName"); + VIRTUAL_FILE_METHOD_GET_PATH_NAME = virtualFile.getMethod("getPathName"); + GET_PHYSICAL_FILE = virtualFile.getMethod("getPhysicalFile"); + VIRTUAL_FILE_METHOD_GET_CHILD = virtualFile.getMethod("getChild", String.class); VIRTUAL_FILE_VISITOR_INTERFACE = loader.loadClass(VFS3_PKG + "VirtualFileVisitor"); - VIRTUAL_FILE_METHOD_VISIT = ReflectionUtils.findMethod(virtualFile, "visit", VIRTUAL_FILE_VISITOR_INTERFACE); + VIRTUAL_FILE_METHOD_VISIT = virtualFile.getMethod("visit", VIRTUAL_FILE_VISITOR_INTERFACE); Class visitorAttributesClass = loader.loadClass(VFS3_PKG + "VisitorAttributes"); - VISITOR_ATTRIBUTES_FIELD_RECURSE = ReflectionUtils.findField(visitorAttributesClass, "RECURSE"); + VISITOR_ATTRIBUTES_FIELD_RECURSE = visitorAttributesClass.getField("RECURSE"); } - catch (ClassNotFoundException ex) { + catch (Exception ex) { throw new IllegalStateException("Could not detect JBoss VFS infrastructure", ex); } } diff --git a/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java b/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java index de4cad0e06..acec012beb 100644 --- a/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java +++ b/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java @@ -221,7 +221,7 @@ public abstract class DataBufferUtils { * @param dataBuffer the data buffer to release * @return {@code true} if the buffer was released; {@code false} otherwise. */ - public static boolean release(DataBuffer dataBuffer) { + public static boolean release(@Nullable DataBuffer dataBuffer) { if (dataBuffer instanceof PooledDataBuffer) { return ((PooledDataBuffer) dataBuffer).release(); } diff --git a/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java b/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java index a016529ee3..9f4bb2c3d0 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java @@ -46,8 +46,10 @@ public class EncodedResource implements InputStreamSource { private final Resource resource; + @Nullable private final String encoding; + @Nullable private final Charset charset; diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java index 63bfec9630..128f532c7f 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java @@ -182,6 +182,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol private static final Log logger = LogFactory.getLog(PathMatchingResourcePatternResolver.class); + @Nullable private static Method equinoxResolveMethod; static { diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java index edaf5686ae..4ba0068ab2 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java @@ -43,14 +43,17 @@ public abstract class PropertiesLoaderSupport { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable protected Properties[] localProperties; protected boolean localOverride = false; + @Nullable private Resource[] locations; private boolean ignoreResourceNotFound = false; + @Nullable private String fileEncoding; private PropertiesPersister propertiesPersister = new DefaultPropertiesPersister(); diff --git a/spring-core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java b/spring-core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java index cfa6785f57..db6917ea72 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java @@ -60,6 +60,7 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport { private final ResourcePatternResolver resourcePatternResolver; + @Nullable private PropertyResolver propertyResolver; private final boolean ignoreUnresolvablePlaceholders; diff --git a/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java b/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java index 580f557ff8..9eff0e3228 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java @@ -45,6 +45,7 @@ import org.springframework.util.StringUtils; public class ResourcePropertySource extends PropertiesPropertySource { /** The original resource name, if different from the given name */ + @Nullable private final String resourceName; diff --git a/spring-core/src/main/java/org/springframework/core/serializer/DefaultDeserializer.java b/spring-core/src/main/java/org/springframework/core/serializer/DefaultDeserializer.java index 8bbf37fff4..df5ca6a367 100644 --- a/spring-core/src/main/java/org/springframework/core/serializer/DefaultDeserializer.java +++ b/spring-core/src/main/java/org/springframework/core/serializer/DefaultDeserializer.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. @@ -22,6 +22,7 @@ import java.io.ObjectInputStream; import org.springframework.core.ConfigurableObjectInputStream; import org.springframework.core.NestedIOException; +import org.springframework.lang.Nullable; /** * A default {@link Deserializer} implementation that reads an input stream @@ -35,6 +36,7 @@ import org.springframework.core.NestedIOException; */ public class DefaultDeserializer implements Deserializer { + @Nullable private final ClassLoader classLoader; @@ -52,7 +54,7 @@ public class DefaultDeserializer implements Deserializer { * @since 4.2.1 * @see ConfigurableObjectInputStream#ConfigurableObjectInputStream(InputStream, ClassLoader) */ - public DefaultDeserializer(ClassLoader classLoader) { + public DefaultDeserializer(@Nullable ClassLoader classLoader) { this.classLoader = classLoader; } diff --git a/spring-core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java b/spring-core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java index 5fecad586a..ff911e40e1 100644 --- a/spring-core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java +++ b/spring-core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.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. @@ -64,8 +64,10 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement /** Internal concurrency throttle used by this executor */ private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter(); + @Nullable private ThreadFactory threadFactory; + @Nullable private TaskDecorator taskDecorator; diff --git a/spring-core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java b/spring-core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java index 72576a02e6..da13b91a1b 100644 --- a/spring-core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java +++ b/spring-core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java @@ -47,6 +47,7 @@ public class TaskExecutorAdapter implements AsyncListenableTaskExecutor { private final Executor concurrentExecutor; + @Nullable private TaskDecorator taskDecorator; diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/AbstractRecursiveAnnotationVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/AbstractRecursiveAnnotationVisitor.java index be98564225..414b1aa1d3 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/AbstractRecursiveAnnotationVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/AbstractRecursiveAnnotationVisitor.java @@ -27,6 +27,7 @@ import org.springframework.asm.SpringAsmInfo; import org.springframework.asm.Type; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.lang.Nullable; +import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; /** @@ -42,6 +43,7 @@ abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor { protected final AnnotationAttributes attributes; + @Nullable protected final ClassLoader classLoader; @@ -79,7 +81,7 @@ abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor { protected Object getEnumValue(String asmTypeDescriptor, String attributeValue) { Object valueToUse = attributeValue; try { - Class enumType = this.classLoader.loadClass(Type.getType(asmTypeDescriptor).getClassName()); + Class enumType = ClassUtils.forName(Type.getType(asmTypeDescriptor).getClassName(), this.classLoader); Field enumConstant = ReflectionUtils.findField(enumType, attributeValue); if (enumConstant != null) { ReflectionUtils.makeAccessible(enumConstant); diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java index ed362883b1..7c85aba97d 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java @@ -47,6 +47,7 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib private final MultiValueMap attributesMap; + @Nullable private final Map> metaAnnotationMap; diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java index 49eb829bad..1158c0dce6 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java @@ -49,6 +49,7 @@ import org.springframework.util.MultiValueMap; */ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata { + @Nullable protected final ClassLoader classLoader; protected final Set annotationSet = new LinkedHashSet<>(4); diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java b/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java index 0f313d9cf2..491e7605cd 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java @@ -41,6 +41,7 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory { public static final int DEFAULT_CACHE_LIMIT = 256; /** MetadataReader cache: either local or shared at the ResourceLoader level */ + @Nullable private Map metadataReaderCache; diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java index 7789c57f63..d3afe98107 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java @@ -44,7 +44,7 @@ import org.springframework.util.ClassUtils; */ class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata { - private String className; + private String className = ""; private boolean isInterface; @@ -54,13 +54,15 @@ class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata private boolean isFinal; + @Nullable private String enclosingClassName; private boolean independentInnerClass; + @Nullable private String superClassName; - private String[] interfaces; + private String[] interfaces = new String[0]; private Set memberClassNames = new LinkedHashSet<>(); @@ -183,6 +185,7 @@ class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata } @Override + @Nullable public String getEnclosingClassName() { return this.enclosingClassName; } @@ -193,6 +196,7 @@ class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata } @Override + @Nullable public String getSuperClassName() { return this.superClassName; } diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/MethodMetadataReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/MethodMetadataReadingVisitor.java index 6727f1db93..fdf8f213de 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/MethodMetadataReadingVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/MethodMetadataReadingVisitor.java @@ -54,14 +54,14 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho protected final String returnTypeName; + @Nullable protected final ClassLoader classLoader; protected final Set methodMetadataSet; protected final Map> metaAnnotationMap = new LinkedHashMap<>(4); - protected final LinkedMultiValueMap attributesMap = - new LinkedMultiValueMap<>(4); + protected final LinkedMultiValueMap attributesMap = new LinkedMultiValueMap<>(4); public MethodMetadataReadingVisitor(String methodName, int access, String declaringClassName, diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/RecursiveAnnotationArrayVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/RecursiveAnnotationArrayVisitor.java index f0c7d20605..e55a05477b 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/RecursiveAnnotationArrayVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/RecursiveAnnotationArrayVisitor.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,6 +23,7 @@ import java.util.List; import org.springframework.asm.AnnotationVisitor; import org.springframework.asm.Type; import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -38,7 +39,7 @@ class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationVisitor public RecursiveAnnotationArrayVisitor( - String attributeName, AnnotationAttributes attributes, ClassLoader classLoader) { + String attributeName, AnnotationAttributes attributes, @Nullable ClassLoader classLoader) { super(classLoader, attributes); this.attributeName = attributeName; diff --git a/spring-core/src/main/java/org/springframework/lang/NonNullApi.java b/spring-core/src/main/java/org/springframework/lang/NonNullApi.java index bee4a0af88..0e823e29c0 100644 --- a/spring-core/src/main/java/org/springframework/lang/NonNullApi.java +++ b/spring-core/src/main/java/org/springframework/lang/NonNullApi.java @@ -26,7 +26,8 @@ import javax.annotation.meta.TypeQualifierDefault; /** * A common Spring annotation to declare that parameters and return values - * are to be considered as non-nullable by default for a given package. + * are to be considered as non-nullable by default for a given package, + * along with their underlying fields. * *

Should be used at package level in association with {@link Nullable} * annotations at parameter and return value level. @@ -35,6 +36,7 @@ import javax.annotation.meta.TypeQualifierDefault; * common tools with JSR-305 support. * * @author Sebastien Deleuze + * @author Juergen Hoeller * @since 5.0 * @see Nullable * @see javax.annotation.Nonnull @@ -43,6 +45,6 @@ import javax.annotation.meta.TypeQualifierDefault; @Retention(RetentionPolicy.RUNTIME) @Documented @Nonnull -@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER}) +@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_PARAMETER, ElementType.FIELD}) public @interface NonNullApi { } diff --git a/spring-core/src/main/java/org/springframework/lang/Nullable.java b/spring-core/src/main/java/org/springframework/lang/Nullable.java index 32e1fd8219..547b3cfd0a 100644 --- a/spring-core/src/main/java/org/springframework/lang/Nullable.java +++ b/spring-core/src/main/java/org/springframework/lang/Nullable.java @@ -26,8 +26,8 @@ import javax.annotation.meta.TypeQualifierNickname; import javax.annotation.meta.When; /** - * A common Spring annotation to declare that the annotated parameter or - * return value could be {@code null} under some circumstances. + * A common Spring annotation to declare that the annotated parameter, + * return value or field could be {@code null} under some circumstances. * *

Should be used at parameters and return values level in association * with {@link NonNullApi} package-level annotations. @@ -36,11 +36,12 @@ import javax.annotation.meta.When; * common tools with JSR-305 support. * * @author Sebastien Deleuze + * @author Juergen Hoeller * @since 5.0 * @see NonNullApi * @see javax.annotation.Nullable */ -@Target({ElementType.METHOD, ElementType.PARAMETER}) +@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_PARAMETER, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Nonnull(when = When.MAYBE) diff --git a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java index b3fbd6b99b..ee784517a0 100644 --- a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java +++ b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java @@ -90,6 +90,7 @@ public class AntPathMatcher implements PathMatcher { private boolean trimTokens = false; + @Nullable private volatile Boolean cachePatterns; private final Map tokenizedPatternCache = new ConcurrentHashMap<>(256); @@ -800,6 +801,7 @@ public class AntPathMatcher implements PathMatcher { */ private static class PatternInfo { + @Nullable private final String pattern; private int uriVars; @@ -812,6 +814,7 @@ public class AntPathMatcher implements PathMatcher { private boolean prefixPattern; + @Nullable private Integer length; public PatternInfo(@Nullable String pattern) { @@ -828,27 +831,29 @@ public class AntPathMatcher implements PathMatcher { protected void initCounters() { int pos = 0; - while (pos < this.pattern.length()) { - if (this.pattern.charAt(pos) == '{') { - this.uriVars++; - pos++; - } - else if (this.pattern.charAt(pos) == '*') { - if (pos + 1 < this.pattern.length() && this.pattern.charAt(pos + 1) == '*') { - this.doubleWildcards++; - pos += 2; - } - else if (pos > 0 && !this.pattern.substring(pos - 1).equals(".*")) { - this.singleWildcards++; + if (this.pattern != null) { + while (pos < this.pattern.length()) { + if (this.pattern.charAt(pos) == '{') { + this.uriVars++; pos++; } + else if (this.pattern.charAt(pos) == '*') { + if (pos + 1 < this.pattern.length() && this.pattern.charAt(pos + 1) == '*') { + this.doubleWildcards++; + pos += 2; + } + else if (pos > 0 && !this.pattern.substring(pos - 1).equals(".*")) { + this.singleWildcards++; + pos++; + } + else { + pos++; + } + } else { pos++; } } - else { - pos++; - } } } @@ -881,7 +886,8 @@ public class AntPathMatcher implements PathMatcher { */ public int getLength() { if (this.length == null) { - this.length = VARIABLE_PATTERN.matcher(this.pattern).replaceAll("#").length(); + this.length = (this.pattern != null ? + VARIABLE_PATTERN.matcher(this.pattern).replaceAll("#").length() : 0); } return this.length; } diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java index b7be3ef641..b646f53ea9 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -116,9 +116,8 @@ public abstract class ClassUtils { Set> primitiveTypes = new HashSet<>(32); primitiveTypes.addAll(primitiveWrapperTypeMap.values()); - primitiveTypes.addAll(Arrays.asList(new Class[] { - boolean[].class, byte[].class, char[].class, double[].class, - float[].class, int[].class, long[].class, short[].class})); + primitiveTypes.addAll(Arrays.asList(boolean[].class, byte[].class, char[].class, + double[].class, float[].class, int[].class, long[].class, short[].class)); primitiveTypes.add(void.class); for (Class primitiveType : primitiveTypes) { primitiveTypeNameMap.put(primitiveType.getName(), primitiveType); @@ -374,7 +373,7 @@ public abstract class ClassUtils { * @param clazz the class to analyze * @param classLoader the ClassLoader to potentially cache metadata in */ - public static boolean isCacheSafe(Class clazz, ClassLoader classLoader) { + public static boolean isCacheSafe(Class clazz, @Nullable ClassLoader classLoader) { Assert.notNull(clazz, "Class must not be null"); try { ClassLoader target = clazz.getClassLoader(); @@ -1222,6 +1221,7 @@ public abstract class ClassUtils { /** * Check whether the given object is a CGLIB proxy. * @param object the object to check + * @see #isCglibProxyClass(Class) * @see org.springframework.aop.support.AopUtils#isCglibProxy(Object) */ public static boolean isCglibProxy(Object object) { @@ -1231,6 +1231,7 @@ public abstract class ClassUtils { /** * Check whether the specified class is a CGLIB-generated class. * @param clazz the class to check + * @see #isCglibProxyClassName(String) */ public static boolean isCglibProxyClass(@Nullable Class clazz) { return (clazz != null && isCglibProxyClassName(clazz.getName())); diff --git a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java index b81211ad70..598b49325c 100644 --- a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java +++ b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java @@ -96,6 +96,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen /** * Late binding entry set. */ + @Nullable private Set> entrySet; @@ -441,9 +442,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen private final int initialSize; /** - * Array of references indexed using the low order bits from the hash. This - * property should only be set via {@link #setReferences} to ensure that the - * {@code resizeThreshold} is maintained. + * Array of references indexed using the low order bits from the hash. + * This property should only be set along with {@code resizeThreshold}. */ private volatile Reference[] references; @@ -462,7 +462,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen public Segment(int initialCapacity) { this.referenceManager = createReferenceManager(); this.initialSize = 1 << calculateShift(initialCapacity, MAXIMUM_SEGMENT_SIZE); - setReferences(createReferenceArray(this.initialSize)); + this.references = createReferenceArray(this.initialSize); + this.resizeThreshold = (int) (this.references.length * getLoadFactor()); } @Nullable @@ -532,7 +533,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen } lock(); try { - setReferences(createReferenceArray(this.initialSize)); + this.references = createReferenceArray(this.initialSize); + this.resizeThreshold = (int) (this.references.length * getLoadFactor()); this.count = 0; } finally { @@ -598,7 +600,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen // Replace volatile members if (resizing) { - setReferences(restructured); + this.references = restructured; + this.resizeThreshold = (int) (this.references.length * getLoadFactor()); } this.count = Math.max(countAfterRestructure, 0); } @@ -636,23 +639,14 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen } /** - * Replace the references with a new value, recalculating the resizeThreshold. - * @param references the new references - */ - private void setReferences(Reference[] references) { - this.references = references; - this.resizeThreshold = (int) (references.length * getLoadFactor()); - } - - /** - * @return the size of the current references array + * Return the size of the current references array. */ public final int getSize() { return this.references.length; } /** - * @return the total number of references in this segment + * Return the total number of references in this segment. */ public final int getCount() { return this.count; @@ -865,12 +859,16 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen private int referenceIndex; + @Nullable private Reference[] references; + @Nullable private Reference reference; + @Nullable private Entry next; + @Nullable private Entry last; public EntryIterator() { @@ -990,9 +988,10 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen private final int hash; + @Nullable private final Reference nextReference; - public SoftEntryReference(Entry entry, int hash, @Nullable Reference next, + public SoftEntryReference(Entry entry, int hash, @Nullable Reference next, ReferenceQueue> queue) { super(entry, queue); @@ -1025,6 +1024,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen private final int hash; + @Nullable private final Reference nextReference; public WeakEntryReference(Entry entry, int hash, @Nullable Reference next, diff --git a/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java b/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java index 1014e7d133..50ed50c317 100644 --- a/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java +++ b/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java @@ -23,6 +23,8 @@ import java.security.MessageDigest; import java.util.Iterator; import java.util.LinkedList; +import org.springframework.lang.Nullable; + /** * A speedy alternative to {@link java.io.ByteArrayOutputStream}. Note that * this variant does not extend {@code ByteArrayOutputStream}, unlike @@ -329,6 +331,7 @@ public class FastByteArrayOutputStream extends OutputStream { private final Iterator buffersIterator; + @Nullable private byte[] currentBuffer; private int currentBufferLength = 0; @@ -350,7 +353,7 @@ public class FastByteArrayOutputStream extends OutputStream { this.currentBufferLength = fastByteArrayOutputStream.index; } else { - this.currentBufferLength = this.currentBuffer.length; + this.currentBufferLength = (this.currentBuffer != null ? this.currentBuffer.length : 0); } } } @@ -369,12 +372,7 @@ public class FastByteArrayOutputStream extends OutputStream { else { if (this.buffersIterator.hasNext()) { this.currentBuffer = this.buffersIterator.next(); - if (this.currentBuffer == this.fastByteArrayOutputStream.buffers.getLast()) { - this.currentBufferLength = this.fastByteArrayOutputStream.index; - } - else { - this.currentBufferLength = this.currentBuffer.length; - } + updateCurrentBufferLength(); this.nextIndexInCurrentBuffer = 0; } else { @@ -421,12 +419,7 @@ public class FastByteArrayOutputStream extends OutputStream { else { if (this.buffersIterator.hasNext()) { this.currentBuffer = this.buffersIterator.next(); - if (this.currentBuffer == this.fastByteArrayOutputStream.buffers.getLast()) { - this.currentBufferLength = this.fastByteArrayOutputStream.index; - } - else { - this.currentBufferLength = this.currentBuffer.length; - } + updateCurrentBufferLength(); this.nextIndexInCurrentBuffer = 0; } else { @@ -464,12 +457,7 @@ public class FastByteArrayOutputStream extends OutputStream { else { if (this.buffersIterator.hasNext()) { this.currentBuffer = this.buffersIterator.next(); - if (this.currentBuffer == this.fastByteArrayOutputStream.buffers.getLast()) { - this.currentBufferLength = this.fastByteArrayOutputStream.index; - } - else { - this.currentBufferLength = this.currentBuffer.length; - } + updateCurrentBufferLength(); this.nextIndexInCurrentBuffer = 0; } else { @@ -520,12 +508,7 @@ public class FastByteArrayOutputStream extends OutputStream { else { if (this.buffersIterator.hasNext()) { this.currentBuffer = this.buffersIterator.next(); - if (this.currentBuffer == this.fastByteArrayOutputStream.buffers.getLast()) { - this.currentBufferLength = this.fastByteArrayOutputStream.index; - } - else { - this.currentBufferLength = this.currentBuffer.length; - } + updateCurrentBufferLength(); this.nextIndexInCurrentBuffer = 0; } else { @@ -535,6 +518,15 @@ public class FastByteArrayOutputStream extends OutputStream { } } } + + private void updateCurrentBufferLength() { + if (this.currentBuffer == this.fastByteArrayOutputStream.buffers.getLast()) { + this.currentBufferLength = this.fastByteArrayOutputStream.index; + } + else { + this.currentBufferLength = (this.currentBuffer != null ? this.currentBuffer.length : 0); + } + } } } diff --git a/spring-core/src/main/java/org/springframework/util/MethodInvoker.java b/spring-core/src/main/java/org/springframework/util/MethodInvoker.java index 07bc24a612..6255cc7a46 100644 --- a/spring-core/src/main/java/org/springframework/util/MethodInvoker.java +++ b/spring-core/src/main/java/org/springframework/util/MethodInvoker.java @@ -38,17 +38,23 @@ import org.springframework.lang.Nullable; */ public class MethodInvoker { + @Nullable protected Class targetClass; + @Nullable private Object targetObject; + @Nullable private String targetMethod; + @Nullable private String staticMethod; + @Nullable private Object[] arguments = new Object[0]; /** The method we will call */ + @Nullable private Method methodObject; diff --git a/spring-core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java b/spring-core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java index cd09f83e31..81d9426dc5 100644 --- a/spring-core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java +++ b/spring-core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java @@ -56,6 +56,7 @@ public class PropertyPlaceholderHelper { private final String simplePrefix; + @Nullable private final String valueSeparator; private final boolean ignoreUnresolvablePlaceholders; diff --git a/spring-core/src/main/java/org/springframework/util/StopWatch.java b/spring-core/src/main/java/org/springframework/util/StopWatch.java index 97dedce033..8cf6a790b7 100644 --- a/spring-core/src/main/java/org/springframework/util/StopWatch.java +++ b/spring-core/src/main/java/org/springframework/util/StopWatch.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. @@ -56,12 +56,11 @@ public class StopWatch { /** Start time of the current task */ private long startTimeMillis; - /** Is the stop watch currently running? */ - private boolean running; - /** Name of the current task */ + @Nullable private String currentTaskName; + @Nullable private TaskInfo lastTaskInfo; private int taskCount; @@ -125,10 +124,9 @@ public class StopWatch { * @see #stop() */ public void start(String taskName) throws IllegalStateException { - if (this.running) { + if (this.currentTaskName != null) { throw new IllegalStateException("Can't start StopWatch: it's already running"); } - this.running = true; this.currentTaskName = taskName; this.startTimeMillis = System.currentTimeMillis(); } @@ -140,17 +138,16 @@ public class StopWatch { * @see #start() */ public void stop() throws IllegalStateException { - if (!this.running) { + if (this.currentTaskName == null) { throw new IllegalStateException("Can't stop StopWatch: it's not running"); } long lastTime = System.currentTimeMillis() - this.startTimeMillis; this.totalTimeMillis += lastTime; this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime); if (this.keepTaskList) { - this.taskList.add(lastTaskInfo); + this.taskList.add(this.lastTaskInfo); } ++this.taskCount; - this.running = false; this.currentTaskName = null; } @@ -159,7 +156,7 @@ public class StopWatch { * @see #currentTaskName() */ public boolean isRunning() { - return this.running; + return (this.currentTaskName != null); } /** diff --git a/spring-core/src/main/java/org/springframework/util/concurrent/FutureAdapter.java b/spring-core/src/main/java/org/springframework/util/concurrent/FutureAdapter.java index 31544eca32..6084418d5d 100644 --- a/spring-core/src/main/java/org/springframework/util/concurrent/FutureAdapter.java +++ b/spring-core/src/main/java/org/springframework/util/concurrent/FutureAdapter.java @@ -38,7 +38,8 @@ public abstract class FutureAdapter implements Future { private final Future adaptee; - private Object result = null; + @Nullable + private Object result; private State state = State.NEW; diff --git a/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java b/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java index e4d310d7ff..b9a9d470a9 100644 --- a/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java +++ b/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.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.util.concurrent; import java.util.LinkedList; import java.util.Queue; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -40,7 +41,8 @@ public class ListenableFutureCallbackRegistry { private State state = State.NEW; - private Object result = null; + @Nullable + private Object result; private final Object mutex = new Object(); @@ -78,6 +80,7 @@ public class ListenableFutureCallbackRegistry { } private void notifyFailure(FailureCallback callback) { + Assert.state(this.result instanceof Throwable, "No Throwable result for failure state"); try { callback.onFailure((Throwable) this.result); } diff --git a/spring-core/src/main/java/org/springframework/util/concurrent/SettableListenableFuture.java b/spring-core/src/main/java/org/springframework/util/concurrent/SettableListenableFuture.java index 563c6160f4..b68e19d5d0 100644 --- a/spring-core/src/main/java/org/springframework/util/concurrent/SettableListenableFuture.java +++ b/spring-core/src/main/java/org/springframework/util/concurrent/SettableListenableFuture.java @@ -145,6 +145,7 @@ public class SettableListenableFuture implements ListenableFuture { private static class SettableTask extends ListenableFutureTask { + @Nullable private volatile Thread completingThread; @SuppressWarnings("unchecked") diff --git a/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxXMLReader.java b/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxXMLReader.java index 6250825375..71488be71e 100644 --- a/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxXMLReader.java +++ b/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxXMLReader.java @@ -56,6 +56,7 @@ abstract class AbstractStaxXMLReader extends AbstractXMLReader { private boolean namespacePrefixesFeature = false; + @Nullable private Boolean isStandalone; private final Map namespaces = new LinkedHashMap<>(); diff --git a/spring-expression/src/main/java/org/springframework/expression/ExpressionException.java b/spring-expression/src/main/java/org/springframework/expression/ExpressionException.java index 4a08e64c41..c0562480a5 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ExpressionException.java +++ b/spring-expression/src/main/java/org/springframework/expression/ExpressionException.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,8 @@ package org.springframework.expression; +import org.springframework.lang.Nullable; + /** * Super class for exceptions that can occur whilst processing expressions. * @@ -26,6 +28,7 @@ package org.springframework.expression; @SuppressWarnings("serial") public class ExpressionException extends RuntimeException { + @Nullable protected String expressionString; protected int position; // -1 if not known; should be known in all reasonable cases @@ -53,7 +56,7 @@ public class ExpressionException extends RuntimeException { * @param expressionString the expression string * @param message a descriptive message */ - public ExpressionException(String expressionString, String message) { + public ExpressionException(@Nullable String expressionString, String message) { super(message); this.expressionString = expressionString; this.position = -1; @@ -65,7 +68,7 @@ public class ExpressionException extends RuntimeException { * @param position the position in the expression string where the problem occurred * @param message a descriptive message */ - public ExpressionException(String expressionString, int position, String message) { + public ExpressionException(@Nullable String expressionString, int position, String message) { super(message); this.expressionString = expressionString; this.position = position; @@ -96,6 +99,7 @@ public class ExpressionException extends RuntimeException { /** * Return the expression string. */ + @Nullable public final String getExpressionString() { return this.expressionString; } diff --git a/spring-expression/src/main/java/org/springframework/expression/ParseException.java b/spring-expression/src/main/java/org/springframework/expression/ParseException.java index 64cb2cadf8..f2a5794496 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ParseException.java +++ b/spring-expression/src/main/java/org/springframework/expression/ParseException.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,8 @@ package org.springframework.expression; +import org.springframework.lang.Nullable; + /** * Represent an exception that occurs during expression parsing. * @@ -31,7 +33,7 @@ public class ParseException extends ExpressionException { * @param position the position in the expression string where the problem occurred * @param message description of the problem that occurred */ - public ParseException(String expressionString, int position, String message) { + public ParseException(@Nullable String expressionString, int position, String message) { super(expressionString, position, message); } diff --git a/spring-expression/src/main/java/org/springframework/expression/TypedValue.java b/spring-expression/src/main/java/org/springframework/expression/TypedValue.java index 376c3025ce..125ff3af9a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/TypedValue.java +++ b/spring-expression/src/main/java/org/springframework/expression/TypedValue.java @@ -34,8 +34,10 @@ public class TypedValue { public static final TypedValue NULL = new TypedValue(null); + @Nullable private final Object value; + @Nullable private TypeDescriptor typeDescriptor; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java b/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java index 1702f681de..88b8743b6c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java @@ -26,7 +26,6 @@ import org.springframework.asm.ClassWriter; import org.springframework.asm.MethodVisitor; import org.springframework.asm.Opcodes; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; /** * Manages the class being generated by the compilation process. @@ -64,6 +63,7 @@ public class CodeFlow implements Opcodes { * they can register to add a field to this class. Any registered FieldAdders * will be called after the main evaluation function has finished being generated. */ + @Nullable private List fieldAdders; /** @@ -72,6 +72,7 @@ public class CodeFlow implements Opcodes { * registered ClinitAdders will be called after the main evaluation function * has finished being generated. */ + @Nullable private List clinitAdders; /** @@ -123,9 +124,10 @@ public class CodeFlow implements Opcodes { * Record the descriptor for the most recently evaluated expression element. * @param descriptor type descriptor for most recently evaluated element */ - public void pushDescriptor(String descriptor) { - Assert.notNull(descriptor, "Descriptor must not be null"); - this.compilationScopes.peek().add(descriptor); + public void pushDescriptor(@Nullable String descriptor) { + if (descriptor != null) { + this.compilationScopes.peek().add(descriptor); + } } /** @@ -236,7 +238,10 @@ public class CodeFlow implements Opcodes { * @param ch the primitive type desired as output * @param stackDescriptor the descriptor of the type on top of the stack */ - public static void insertUnboxInsns(MethodVisitor mv, char ch, String stackDescriptor) { + public static void insertUnboxInsns(MethodVisitor mv, char ch, @Nullable String stackDescriptor) { + if (stackDescriptor == null) { + return; + } switch (ch) { case 'Z': if (!stackDescriptor.equals("Ljava/lang/Boolean")) { @@ -297,7 +302,13 @@ public class CodeFlow implements Opcodes { * @param targetDescriptor the primitive type desired as output * @param stackDescriptor the descriptor of the type on top of the stack */ - public static void insertUnboxNumberInsns(MethodVisitor mv, char targetDescriptor, String stackDescriptor) { + public static void insertUnboxNumberInsns( + MethodVisitor mv, char targetDescriptor, @Nullable String stackDescriptor) { + + if (stackDescriptor == null) { + return; + } + switch (targetDescriptor) { case 'D': if (stackDescriptor.equals("Ljava/lang/Object")) { @@ -510,7 +521,6 @@ public class CodeFlow implements Opcodes { * @return the type descriptor for the object * (descriptor is "Ljava/lang/Object" for {@code null} value) */ - @Nullable public static String toDescriptorFromObject(@Nullable Object value) { if (value == null) { return "Ljava/lang/Object"; @@ -540,7 +550,10 @@ public class CodeFlow implements Opcodes { * @param descriptor the descriptor for a possible primitive array * @return {@code true} if the descriptor is for a primitive array (e.g. "[[I") */ - public static boolean isPrimitiveArray(String descriptor) { + public static boolean isPrimitiveArray(@Nullable String descriptor) { + if (descriptor == null) { + return false; + } boolean primitive = true; for (int i = 0, max = descriptor.length(); i < max; i++) { char ch = descriptor.charAt(i); @@ -691,8 +704,8 @@ public class CodeFlow implements Opcodes { * @param mv the target visitor into which the instruction should be inserted * @param descriptor the descriptor of the type to cast to */ - public static void insertCheckCast(MethodVisitor mv, String descriptor) { - if (descriptor.length() != 1) { + public static void insertCheckCast(MethodVisitor mv, @Nullable String descriptor) { + if (descriptor != null && descriptor.length() != 1) { if (descriptor.charAt(0) == '[') { if (isPrimitiveArray(descriptor)) { mv.visitTypeInsn(CHECKCAST, descriptor); @@ -771,7 +784,6 @@ public class CodeFlow implements Opcodes { * @param type the type (may be primitive) for which to determine the descriptor * @return the descriptor */ - @Nullable public static String toDescriptor(Class type) { String name = type.getName(); if (type.isPrimitive()) { @@ -825,7 +837,7 @@ public class CodeFlow implements Opcodes { } } } - return null; + return ""; } /** @@ -982,7 +994,7 @@ public class CodeFlow implements Opcodes { * @param targetDescriptor a primitive type descriptor */ public static void insertNumericUnboxOrPrimitiveTypeCoercion( - MethodVisitor mv, String stackDescriptor, char targetDescriptor) { + MethodVisitor mv, @Nullable String stackDescriptor, char targetDescriptor) { if (!CodeFlow.isPrimitive(stackDescriptor)) { CodeFlow.insertUnboxNumberInsns(mv, targetDescriptor, stackDescriptor); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java b/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java index 38ecd37c65..142a1992e8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java @@ -33,6 +33,7 @@ import org.springframework.expression.TypeConverter; import org.springframework.expression.TypedValue; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; /** * An ExpressionState is for maintaining per-expression-evaluation state, any changes to @@ -54,6 +55,14 @@ public class ExpressionState { private final TypedValue rootObject; + private final SpelParserConfiguration configuration; + + @Nullable + private Stack contextObjects; + + @Nullable + private Stack variableScopes; + // When entering a new scope there is a new base object which should be used // for '#this' references (or to act as a target for unqualified references). // This stack captures those objects at each nested scope level. @@ -61,14 +70,9 @@ public class ExpressionState { // #list1.?[#list2.contains(#this)] // On entering the selection we enter a new scope, and #this is now the // element from list1 + @Nullable private Stack scopeRootObjects; - private final SpelParserConfiguration configuration; - - private Stack variableScopes; - - private Stack contextObjects; - public ExpressionState(EvaluationContext context) { this(context, context.getRootObject(), new SpelParserConfiguration(false, false)); @@ -91,22 +95,11 @@ public class ExpressionState { } - private void ensureVariableScopesInitialized() { - if (this.variableScopes == null) { - this.variableScopes = new Stack<>(); - // top level empty variable scope - this.variableScopes.add(new VariableScope()); - } - if (this.scopeRootObjects == null) { - this.scopeRootObjects = new Stack<>(); - } - } - /** * The active context object is what unqualified references to properties/etc are resolved against. */ public TypedValue getActiveContextObject() { - if (this.contextObjects == null || this.contextObjects.isEmpty()) { + if (CollectionUtils.isEmpty(this.contextObjects)) { return this.rootObject; } return this.contextObjects.peek(); @@ -131,7 +124,7 @@ public class ExpressionState { } public TypedValue getScopeRootContextObject() { - if (this.scopeRootObjects == null || this.scopeRootObjects.isEmpty()) { + if (CollectionUtils.isEmpty(this.scopeRootObjects)) { return this.rootObject; } return this.scopeRootObjects.peek(); @@ -177,46 +170,57 @@ public class ExpressionState { * A new scope is entered when a function is invoked. */ public void enterScope(Map argMap) { - ensureVariableScopesInitialized(); - this.variableScopes.push(new VariableScope(argMap)); - this.scopeRootObjects.push(getActiveContextObject()); + initVariableScopes().push(new VariableScope(argMap)); + initScopeRootObjects().push(getActiveContextObject()); } public void enterScope() { - ensureVariableScopesInitialized(); - this.variableScopes.push(new VariableScope(Collections.emptyMap())); - this.scopeRootObjects.push(getActiveContextObject()); + initVariableScopes().push(new VariableScope(Collections.emptyMap())); + initScopeRootObjects().push(getActiveContextObject()); } public void enterScope(String name, Object value) { - ensureVariableScopesInitialized(); - this.variableScopes.push(new VariableScope(name, value)); - this.scopeRootObjects.push(getActiveContextObject()); + initVariableScopes().push(new VariableScope(name, value)); + initScopeRootObjects().push(getActiveContextObject()); } public void exitScope() { - ensureVariableScopesInitialized(); - this.variableScopes.pop(); - this.scopeRootObjects.pop(); + initVariableScopes().pop(); + initScopeRootObjects().pop(); } public void setLocalVariable(String name, Object value) { - ensureVariableScopesInitialized(); - this.variableScopes.peek().setVariable(name, value); + initVariableScopes().peek().setVariable(name, value); } @Nullable public Object lookupLocalVariable(String name) { - ensureVariableScopesInitialized(); - int scopeNumber = this.variableScopes.size() - 1; + int scopeNumber = initVariableScopes().size() - 1; for (int i = scopeNumber; i >= 0; i--) { - if (this.variableScopes.get(i).definesVariable(name)) { - return this.variableScopes.get(i).lookupVariable(name); + VariableScope scope = initVariableScopes().get(i); + if (scope.definesVariable(name)) { + return scope.lookupVariable(name); } } return null; } + private Stack initVariableScopes() { + if (this.variableScopes == null) { + this.variableScopes = new Stack<>(); + // top level empty variable scope + this.variableScopes.add(new VariableScope()); + } + return this.variableScopes; + } + + private Stack initScopeRootObjects() { + if (this.scopeRootObjects == null) { + this.scopeRootObjects = new Stack<>(); + } + return this.scopeRootObjects; + } + public TypedValue operate(Operation op, @Nullable Object left, @Nullable Object right) throws EvaluationException { OperatorOverloader overloader = this.relatedContext.getOperatorOverloader(); if (overloader.overridesOperation(op, left, right)) { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.java index 5a045a9199..2b0ddb605a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.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.expression.spel; import org.springframework.expression.ParseException; +import org.springframework.lang.Nullable; /** * Root exception for Spring EL related exceptions. Rather than holding a hard coded @@ -35,7 +36,7 @@ public class SpelParseException extends ParseException { private final Object[] inserts; - public SpelParseException(String expressionString, int position, SpelMessage message, Object... inserts) { + public SpelParseException(@Nullable String expressionString, int position, SpelMessage message, Object... inserts) { super(expressionString, position, message.formatMessage(inserts)); this.message = message; this.inserts = inserts; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java index f57e3341a4..a1f9a2b5c1 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java @@ -41,6 +41,7 @@ public class SpelParserConfiguration { private final SpelCompilerMode compilerMode; + @Nullable private final ClassLoader compilerClassLoader; private final boolean autoGrowNullReferences; @@ -106,35 +107,36 @@ public class SpelParserConfiguration { /** - * @return the configuration mode for parsers using this configuration object + * Return the configuration mode for parsers using this configuration object. */ public SpelCompilerMode getCompilerMode() { return this.compilerMode; } /** - * @return the ClassLoader to use as the basis for expression compilation + * Return the ClassLoader to use as the basis for expression compilation. */ + @Nullable public ClassLoader getCompilerClassLoader() { return this.compilerClassLoader; } /** - * @return {@code true} if {@code null} references should be automatically grown + * Return {@code true} if {@code null} references should be automatically grown. */ public boolean isAutoGrowNullReferences() { return this.autoGrowNullReferences; } /** - * @return {@code true} if collections should be automatically grown + * Return {@code true} if collections should be automatically grown. */ public boolean isAutoGrowCollections() { return this.autoGrowCollections; } /** - * @return the maximum size that a collection can auto grow + * Return the maximum size that a collection can auto grow. */ public int getMaximumAutoGrowSize() { return this.maximumAutoGrowSize; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java index 6702148270..545f865d97 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.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. @@ -37,7 +37,7 @@ public class BeanReference extends SpelNodeImpl { private final String beanName; - public BeanReference(int pos,String beanName) { + public BeanReference(int pos, String beanName) { super(pos); this.beanName = beanName; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java index d97b7b8610..bcc3bc901e 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java @@ -39,6 +39,7 @@ import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.SpelNode; import org.springframework.expression.spel.support.ReflectiveConstructorExecutor; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -58,12 +59,12 @@ public class ConstructorReference extends SpelNodeImpl { private boolean isArrayConstructor = false; + @Nullable private SpelNodeImpl[] dimensions; // TODO is this caching safe - passing the expression around will mean this executor is also being passed around - /** - * The cached executor that may be reused on subsequent evaluations. - */ + /** The cached executor that may be reused on subsequent evaluations */ + @Nullable private volatile ConstructorExecutor cachedExecutor; @@ -157,9 +158,9 @@ public class ConstructorReference extends SpelNodeImpl { executorToUse = findExecutorForConstructor(typeName, argumentTypes, state); try { this.cachedExecutor = executorToUse; - if (this.cachedExecutor instanceof ReflectiveConstructorExecutor) { + if (executorToUse instanceof ReflectiveConstructorExecutor) { this.exitTypeDescriptor = CodeFlow.toDescriptor( - ((ReflectiveConstructorExecutor) this.cachedExecutor).getConstructor().getDeclaringClass()); + ((ReflectiveConstructorExecutor) executorToUse).getConstructor().getDeclaringClass()); } return executorToUse.execute(state.getEvaluationContext(), arguments); @@ -245,9 +246,11 @@ public class ConstructorReference extends SpelNodeImpl { Object newArray; if (!hasInitializer()) { // Confirm all dimensions were specified (for example [3][][5] is missing the 2nd dimension) - for (SpelNodeImpl dimension : this.dimensions) { - if (dimension == null) { - throw new SpelEvaluationException(getStartPosition(), SpelMessage.MISSING_ARRAY_DIMENSION); + if (this.dimensions != null) { + for (SpelNodeImpl dimension : this.dimensions) { + if (dimension == null) { + throw new SpelEvaluationException(getStartPosition(), SpelMessage.MISSING_ARRAY_DIMENSION); + } } } TypeConverter typeConverter = state.getEvaluationContext().getTypeConverter(); @@ -270,7 +273,7 @@ public class ConstructorReference extends SpelNodeImpl { } else { // There is an initializer - if (this.dimensions.length > 1) { + if (this.dimensions == null || this.dimensions.length > 1) { // There is an initializer but this is a multi-dimensional array (e.g. new int[][]{{1,2},{3,4}}) - this // is not currently supported throw new SpelEvaluationException(getStartPosition(), @@ -436,6 +439,9 @@ public class ConstructorReference extends SpelNodeImpl { } ReflectiveConstructorExecutor executor = (ReflectiveConstructorExecutor) this.cachedExecutor; + if (executor == null) { + return false; + } Constructor constructor = executor.getConstructor(); return (Modifier.isPublic(constructor.getModifiers()) && Modifier.isPublic(constructor.getDeclaringClass().getModifiers())); @@ -444,10 +450,13 @@ public class ConstructorReference extends SpelNodeImpl { @Override public void generateCode(MethodVisitor mv, CodeFlow cf) { ReflectiveConstructorExecutor executor = ((ReflectiveConstructorExecutor) this.cachedExecutor); - Constructor constructor = executor.getConstructor(); + Assert.state(executor != null, "No cached executor"); + + Constructor constructor = executor.getConstructor(); String classDesc = constructor.getDeclaringClass().getName().replace('.', '/'); mv.visitTypeInsn(NEW, classDesc); mv.visitInsn(DUP); + // children[0] is the type of the constructor, don't want to include that in argument processing SpelNodeImpl[] arguments = new SpelNodeImpl[children.length - 1]; System.arraycopy(children, 1, arguments, 0, children.length - 1); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java index 774594968a..28c74aba2e 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java @@ -23,6 +23,7 @@ import org.springframework.expression.TypedValue; import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -109,7 +110,7 @@ public class Elvis extends SpelNodeImpl { this.children[1].exitTypeDescriptor != null) { String conditionDescriptor = this.children[0].exitTypeDescriptor; String ifNullValueDescriptor = this.children[1].exitTypeDescriptor; - if (conditionDescriptor.equals(ifNullValueDescriptor)) { + if (ObjectUtils.nullSafeEquals(conditionDescriptor, ifNullValueDescriptor)) { this.exitTypeDescriptor = conditionDescriptor; } else { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java index 61dcc13a51..aa9ff91666 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java @@ -30,6 +30,8 @@ import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.support.ReflectionHelper; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -53,6 +55,7 @@ public class FunctionReference extends SpelNodeImpl { // Captures the most recently used method for the function invocation *if* the method // can safely be used for compilation (i.e. no argument conversion is going on) + @Nullable private Method method; private boolean argumentConversionOccurred; @@ -177,6 +180,7 @@ public class FunctionReference extends SpelNodeImpl { @Override public void generateCode(MethodVisitor mv,CodeFlow cf) { + Assert.state(this.method != null, "No method handle"); String classDesc = this.method.getDeclaringClass().getName().replace('.', '/'); generateCodeForArguments(mv, cf, this.method, this.children); mv.visitMethodInsn(INVOKESTATIC, classDesc, this.method.getName(), diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java index 8c133a5416..c0d3d9aef2 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java @@ -54,7 +54,7 @@ import org.springframework.util.ReflectionUtils; // TODO support correct syntax for multidimensional [][][] and not [,,,] public class Indexer extends SpelNodeImpl { - private static enum IndexedType {ARRAY, LIST, MAP, STRING, OBJECT} + private enum IndexedType {ARRAY, LIST, MAP, STRING, OBJECT} // These fields are used when the indexer is being used as a property read accessor. @@ -62,10 +62,13 @@ public class Indexer extends SpelNodeImpl { // is used to read the property. If they do not match, the correct accessor is // discovered and then cached for later use. + @Nullable private String cachedReadName; + @Nullable private Class cachedReadTargetType; + @Nullable private PropertyAccessor cachedReadAccessor; // These fields are used when the indexer is being used as a property write accessor. @@ -73,12 +76,16 @@ public class Indexer extends SpelNodeImpl { // is used to write the property. If they do not match, the correct accessor is // discovered and then cached for later use. + @Nullable private String cachedWriteName; + @Nullable private Class cachedWriteTargetType; + @Nullable private PropertyAccessor cachedWriteAccessor; + @Nullable private IndexedType indexedType; @@ -282,6 +289,7 @@ public class Indexer extends SpelNodeImpl { else if (this.indexedType == IndexedType.OBJECT) { ReflectivePropertyAccessor.OptimalPropertyAccessor accessor = (ReflectivePropertyAccessor.OptimalPropertyAccessor) this.cachedReadAccessor; + Assert.state(accessor != null, "No cached read accessor"); Member member = accessor.member; boolean isStatic = Modifier.isStatic(member.getModifiers()); String classDesc = member.getDeclaringClass().getName().replace('.', '/'); @@ -493,6 +501,7 @@ public class Indexer extends SpelNodeImpl { private final Map map; + @Nullable private final Object key; private final TypeDescriptor mapEntryDescriptor; @@ -556,7 +565,9 @@ public class Indexer extends SpelNodeImpl { Indexer.this.cachedReadTargetType != null && Indexer.this.cachedReadTargetType.equals(targetObjectRuntimeClass)) { // It is OK to use the cached accessor - return Indexer.this.cachedReadAccessor.read(this.evaluationContext, this.targetObject, this.name); + PropertyAccessor accessor = Indexer.this.cachedReadAccessor; + Assert.state(accessor != null, "No cached read accessor"); + return accessor.read(this.evaluationContext, this.targetObject, this.name); } List accessorsToTry = AstUtils.getPropertyAccessorsToTry( targetObjectRuntimeClass, this.evaluationContext.getPropertyAccessors()); @@ -596,7 +607,9 @@ public class Indexer extends SpelNodeImpl { Indexer.this.cachedWriteTargetType != null && Indexer.this.cachedWriteTargetType.equals(contextObjectClass)) { // It is OK to use the cached accessor - Indexer.this.cachedWriteAccessor.write(this.evaluationContext, this.targetObject, this.name, newValue); + PropertyAccessor accessor = Indexer.this.cachedWriteAccessor; + Assert.state(accessor != null, "No cached write accessor"); + accessor.write(this.evaluationContext, this.targetObject, this.name, newValue); return; } List accessorsToTry = diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java index 26a43c5d38..20dafbc018 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java @@ -27,6 +27,7 @@ import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelNode; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Represent a list in an expression, e.g. '{1,2,3}' @@ -37,7 +38,8 @@ import org.springframework.lang.Nullable; public class InlineList extends SpelNodeImpl { // If the list is purely literals, it is a constant value and can be computed and cached - private TypedValue constant = null; // TODO must be immutable list + @Nullable + private TypedValue constant; // TODO must be immutable list public InlineList(int pos, SpelNodeImpl... args) { @@ -123,6 +125,7 @@ public class InlineList extends SpelNodeImpl { @SuppressWarnings("unchecked") @Nullable public List getConstantValue() { + Assert.state(this.constant != null, "No constant"); return (List) this.constant.getValue(); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java index 9e475e1dfa..3ebf755fb9 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java @@ -25,6 +25,7 @@ import org.springframework.expression.TypedValue; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelNode; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Represent a map in an expression, e.g. '{name:'foo',age:12}' @@ -35,7 +36,8 @@ import org.springframework.lang.Nullable; public class InlineMap extends SpelNodeImpl { // If the map is purely literals, it is a constant value and can be computed and cached - private TypedValue constant = null; + @Nullable + private TypedValue constant; public InlineMap(int pos, SpelNodeImpl... args) { @@ -149,7 +151,7 @@ public class InlineMap extends SpelNodeImpl { } /** - * @return whether this list is a constant value + * Return whether this list is a constant value. */ public boolean isConstant() { return this.constant != null; @@ -158,6 +160,7 @@ public class InlineMap extends SpelNodeImpl { @SuppressWarnings("unchecked") @Nullable public Map getConstantValue() { + Assert.state(this.constant != null, "No constant"); return (Map) this.constant.getValue(); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java index 6ac1a47d32..23b82ceea3 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Literal.java @@ -32,6 +32,7 @@ import org.springframework.lang.Nullable; */ public abstract class Literal extends SpelNodeImpl { + @Nullable private final String originalValue; @@ -41,6 +42,7 @@ public abstract class Literal extends SpelNodeImpl { } + @Nullable public final String getOriginalValue() { return this.originalValue; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java index 0f719b0129..4ee22d6468 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.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. @@ -55,6 +55,7 @@ public class MethodReference extends SpelNodeImpl { private final boolean nullSafe; + @Nullable private volatile CachedMethodExecutor cachedExecutor; @@ -338,8 +339,10 @@ public class MethodReference extends SpelNodeImpl { private final EvaluationContext evaluationContext; + @Nullable private final Object value; + @Nullable private final TypeDescriptor targetType; private final Object[] arguments; @@ -360,7 +363,7 @@ public class MethodReference extends SpelNodeImpl { } @Override - public void setValue(Object newValue) { + public void setValue(@Nullable Object newValue) { throw new IllegalAccessError(); } @@ -375,8 +378,10 @@ public class MethodReference extends SpelNodeImpl { private final MethodExecutor methodExecutor; + @Nullable private final Class staticClass; + @Nullable private final TypeDescriptor target; private final List argumentTypes; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java index 448094cd4d..2b9d4fc069 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.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. @@ -26,6 +26,7 @@ import org.springframework.expression.Operation; import org.springframework.expression.TypedValue; import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; +import org.springframework.util.Assert; import org.springframework.util.NumberUtils; /** @@ -105,14 +106,17 @@ public class OpDivide extends Operator { public void generateCode(MethodVisitor mv, CodeFlow cf) { getLeftOperand().generateCode(mv, cf); String leftDesc = getLeftOperand().exitTypeDescriptor; - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, this.exitTypeDescriptor.charAt(0)); + String exitDesc = this.exitTypeDescriptor; + Assert.state(exitDesc != null, "No exit type descriptor"); + char targetDesc = exitDesc.charAt(0); + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, targetDesc); if (this.children.length > 1) { cf.enterCompilationScope(); getRightOperand().generateCode(mv, cf); String rightDesc = getRightOperand().exitTypeDescriptor; cf.exitCompilationScope(); - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, this.exitTypeDescriptor.charAt(0)); - switch (this.exitTypeDescriptor.charAt(0)) { + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, targetDesc); + switch (targetDesc) { case 'I': mv.visitInsn(IDIV); break; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java index 2216ce22b4..90c5309e39 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java @@ -25,6 +25,7 @@ import org.springframework.expression.Operation; import org.springframework.expression.TypedValue; import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; +import org.springframework.util.Assert; import org.springframework.util.NumberUtils; /** @@ -176,14 +177,17 @@ public class OpMinus extends Operator { public void generateCode(MethodVisitor mv, CodeFlow cf) { getLeftOperand().generateCode(mv, cf); String leftDesc = getLeftOperand().exitTypeDescriptor; - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, this.exitTypeDescriptor.charAt(0)); + String exitDesc = this.exitTypeDescriptor; + Assert.state(exitDesc != null, "No exit type descriptor"); + char targetDesc = exitDesc.charAt(0); + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, targetDesc); if (this.children.length > 1) { cf.enterCompilationScope(); getRightOperand().generateCode(mv, cf); String rightDesc = getRightOperand().exitTypeDescriptor; cf.exitCompilationScope(); - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, this.exitTypeDescriptor.charAt(0)); - switch (this.exitTypeDescriptor.charAt(0)) { + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, targetDesc); + switch (targetDesc) { case 'I': mv.visitInsn(ISUB); break; @@ -202,7 +206,7 @@ public class OpMinus extends Operator { } } else { - switch (this.exitTypeDescriptor.charAt(0)) { + switch (targetDesc) { case 'I': mv.visitInsn(INEG); break; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java index 1ed4a956a8..cab9be9873 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.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. @@ -25,6 +25,7 @@ import org.springframework.expression.Operation; import org.springframework.expression.TypedValue; import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; +import org.springframework.util.Assert; import org.springframework.util.NumberUtils; /** @@ -103,14 +104,17 @@ public class OpModulus extends Operator { public void generateCode(MethodVisitor mv, CodeFlow cf) { getLeftOperand().generateCode(mv, cf); String leftDesc = getLeftOperand().exitTypeDescriptor; - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, this.exitTypeDescriptor.charAt(0)); + String exitDesc = this.exitTypeDescriptor; + Assert.state(exitDesc != null, "No exit type descriptor"); + char targetDesc = exitDesc.charAt(0); + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, targetDesc); if (this.children.length > 1) { cf.enterCompilationScope(); getRightOperand().generateCode(mv, cf); String rightDesc = getRightOperand().exitTypeDescriptor; cf.exitCompilationScope(); - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, this.exitTypeDescriptor.charAt(0)); - switch (this.exitTypeDescriptor.charAt(0)) { + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, targetDesc); + switch (targetDesc) { case 'I': mv.visitInsn(IREM); break; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java index 1c7fe93adf..16491e7722 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.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. @@ -25,6 +25,7 @@ import org.springframework.expression.Operation; import org.springframework.expression.TypedValue; import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; +import org.springframework.util.Assert; import org.springframework.util.NumberUtils; /** @@ -136,14 +137,17 @@ public class OpMultiply extends Operator { public void generateCode(MethodVisitor mv, CodeFlow cf) { getLeftOperand().generateCode(mv, cf); String leftDesc = getLeftOperand().exitTypeDescriptor; - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, this.exitTypeDescriptor.charAt(0)); + String exitDesc = this.exitTypeDescriptor; + Assert.state(exitDesc != null, "No exit type descriptor"); + char targetDesc = exitDesc.charAt(0); + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, targetDesc); if (this.children.length > 1) { cf.enterCompilationScope(); getRightOperand().generateCode(mv, cf); String rightDesc = getRightOperand().exitTypeDescriptor; cf.exitCompilationScope(); - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, this.exitTypeDescriptor.charAt(0)); - switch (this.exitTypeDescriptor.charAt(0)) { + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, targetDesc); + switch (targetDesc) { case 'I': mv.visitInsn(IMUL); break; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java index 0a9bf982a3..b5f752ca48 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java @@ -219,14 +219,17 @@ public class OpPlus extends Operator { else { this.children[0].generateCode(mv, cf); String leftDesc = this.children[0].exitTypeDescriptor; - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, this.exitTypeDescriptor.charAt(0)); + String exitDesc = this.exitTypeDescriptor; + Assert.state(exitDesc != null, "No exit type descriptor"); + char targetDesc = exitDesc.charAt(0); + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, leftDesc, targetDesc); if (this.children.length > 1) { cf.enterCompilationScope(); this.children[1].generateCode(mv, cf); String rightDesc = this.children[1].exitTypeDescriptor; cf.exitCompilationScope(); - CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, this.exitTypeDescriptor.charAt(0)); - switch (this.exitTypeDescriptor.charAt(0)) { + CodeFlow.insertNumericUnboxOrPrimitiveTypeCoercion(mv, rightDesc, targetDesc); + switch (targetDesc) { case 'I': mv.visitInsn(IADD); break; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java index 24e9d33767..90d345334f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java @@ -47,8 +47,10 @@ public abstract class Operator extends SpelNodeImpl { // whose accessors seem to only be returning 'Object' - the actual descriptors may // indicate 'int') + @Nullable protected String leftActualDescriptor; + @Nullable protected String rightActualDescriptor; @@ -266,8 +268,9 @@ public abstract class Operator extends SpelNodeImpl { * @param rightActualDescriptor the dynamic/runtime right object descriptor * @return a DescriptorComparison object indicating the type of compatibility, if any */ - public static DescriptorComparison checkNumericCompatibility(String leftDeclaredDescriptor, - String rightDeclaredDescriptor, String leftActualDescriptor, String rightActualDescriptor) { + public static DescriptorComparison checkNumericCompatibility( + @Nullable String leftDeclaredDescriptor, @Nullable String rightDeclaredDescriptor, + @Nullable String leftActualDescriptor, @Nullable String rightActualDescriptor) { String ld = leftDeclaredDescriptor; String rd = rightDeclaredDescriptor; @@ -276,11 +279,11 @@ public abstract class Operator extends SpelNodeImpl { boolean rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd); // If the declared descriptors aren't providing the information, try the actual descriptors - if (!leftNumeric && !ld.equals(leftActualDescriptor)) { + if (!leftNumeric && !ObjectUtils.nullSafeEquals(ld, leftActualDescriptor)) { ld = leftActualDescriptor; leftNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(ld); } - if (!rightNumeric && !rd.equals(rightActualDescriptor)) { + if (!rightNumeric && !ObjectUtils.nullSafeEquals(rd, rightActualDescriptor)) { rd = rightActualDescriptor; rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java index 0689384af4..e2ca2f2312 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.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. @@ -53,8 +53,10 @@ public class PropertyOrFieldReference extends SpelNodeImpl { private final String name; + @Nullable private volatile PropertyAccessor cachedReadAccessor; + @Nullable private volatile PropertyAccessor cachedWriteAccessor; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java index bba31cc30a..9b7e01efcc 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java @@ -19,6 +19,7 @@ package org.springframework.expression.spel.ast; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; import org.springframework.expression.spel.ExpressionState; +import org.springframework.lang.Nullable; /** * Represents a dot separated sequence of strings that indicate a package qualified type @@ -31,7 +32,7 @@ import org.springframework.expression.spel.ExpressionState; */ public class QualifiedIdentifier extends SpelNodeImpl { - // TODO safe to cache? dont think so + @Nullable private TypedValue value; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java index 99c522bb78..63217330dd 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java @@ -50,6 +50,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN; + @Nullable private SpelNodeImpl parent; /** @@ -61,6 +62,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { * It does not include the trailing semicolon (for non array reference types). * Some examples: Ljava/lang/String, I, [I */ + @Nullable protected volatile String exitTypeDescriptor; @@ -182,6 +184,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { throw new IllegalStateException(getClass().getName() +" has no generateCode(..) method"); } + @Nullable public String getExitDescriptor() { return this.exitTypeDescriptor; } @@ -222,25 +225,25 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { generateCodeForArgument(mv, cf, arguments[p], paramDescriptors[p]); } - SpelNodeImpl lastchild = (childCount == 0 ? null : arguments[childCount - 1]); - String arraytype = paramDescriptors[paramDescriptors.length - 1]; + SpelNodeImpl lastChild = (childCount == 0 ? null : arguments[childCount - 1]); + String arrayType = paramDescriptors[paramDescriptors.length - 1]; // Determine if the final passed argument is already suitably packaged in array // form to be passed to the method - if (lastchild != null && lastchild.getExitDescriptor().equals(arraytype)) { - generateCodeForArgument(mv, cf, lastchild, paramDescriptors[p]); + if (lastChild != null && arrayType.equals(lastChild.getExitDescriptor())) { + generateCodeForArgument(mv, cf, lastChild, paramDescriptors[p]); } else { - arraytype = arraytype.substring(1); // trim the leading '[', may leave other '[' + arrayType = arrayType.substring(1); // trim the leading '[', may leave other '[' // build array big enough to hold remaining arguments - CodeFlow.insertNewArrayCode(mv, childCount - p, arraytype); + CodeFlow.insertNewArrayCode(mv, childCount - p, arrayType); // Package up the remaining arguments into the array int arrayindex = 0; while (p < childCount) { SpelNodeImpl child = arguments[p]; mv.visitInsn(DUP); CodeFlow.insertOptimalLoad(mv, arrayindex++); - generateCodeForArgument(mv, cf, child, arraytype); - CodeFlow.insertArrayStore(mv, arraytype); + generateCodeForArgument(mv, cf, child, arrayType); + CodeFlow.insertArrayStore(mv, arrayType); p++; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java index 373c116722..d058ec9efa 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java @@ -25,6 +25,7 @@ import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** * Represents a ternary expression, for example: "someCheck()?true:false". @@ -69,7 +70,7 @@ public class Ternary extends SpelNodeImpl { this.children[2].exitTypeDescriptor != null) { String leftDescriptor = this.children[1].exitTypeDescriptor; String rightDescriptor = this.children[2].exitTypeDescriptor; - if (leftDescriptor.equals(rightDescriptor)) { + if (ObjectUtils.nullSafeEquals(leftDescriptor, rightDescriptor)) { this.exitTypeDescriptor = leftDescriptor; } else { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java index aa59628992..06d642a74e 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.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. @@ -153,7 +153,7 @@ public class VariableReference extends SpelNodeImpl { mv.visitLdcInsn(name); mv.visitMethodInsn(INVOKEINTERFACE, "org/springframework/expression/EvaluationContext", "lookupVariable", "(Ljava/lang/String;)Ljava/lang/Object;",true); } - CodeFlow.insertCheckCast(mv,this.exitTypeDescriptor); + CodeFlow.insertCheckCast(mv, this.exitTypeDescriptor); cf.pushDescriptor(this.exitTypeDescriptor); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java index d817bc6730..9c62e82d62 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java @@ -17,6 +17,7 @@ package org.springframework.expression.spel.standard; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Stack; @@ -95,10 +96,10 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { private final Stack constructedNodes = new Stack<>(); // The expression being parsed - private String expressionString; + private String expressionString = ""; // The token stream constructed from that expression string - private List tokenStream; + private List tokenStream = Collections.emptyList(); // length of a populated token stream private int tokenStreamLength; @@ -117,7 +118,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { @Override - protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException { + protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) + throws ParseException { + try { this.expressionString = expressionString; Tokenizer tokenizer = new Tokenizer(expressionString); @@ -127,8 +130,10 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { this.tokenStreamPointer = 0; this.constructedNodes.clear(); SpelNodeImpl ast = eatExpression(); - if (moreTokens()) { - throw new SpelParseException(peekToken().startPos, SpelMessage.MORE_INPUT, toString(nextToken())); + Assert.state(ast != null, "No node"); + Token t = peekToken(); + if (t != null) { + throw new SpelParseException(t.startPos, SpelMessage.MORE_INPUT, toString(nextToken())); } Assert.isTrue(this.constructedNodes.isEmpty(), "At least one node expected"); return new SpelExpression(expressionString, ast, this.configuration); @@ -144,10 +149,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { // | (DEFAULT^ logicalOrExpression) // | (QMARK^ expression COLON! expression) // | (ELVIS^ expression))?; + @Nullable private SpelNodeImpl eatExpression() { SpelNodeImpl expr = eatLogicalOrExpression(); - if (moreTokens()) { - Token t = peekToken(); + Token t = peekToken(); + if (t != null) { if (t.kind == TokenKind.ASSIGN) { // a=b if (expr == null) { expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 1)); @@ -182,10 +188,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } //logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*; + @Nullable private SpelNodeImpl eatLogicalOrExpression() { SpelNodeImpl expr = eatLogicalAndExpression(); while (peekIdentifierToken("or") || peekToken(TokenKind.SYMBOLIC_OR)) { - Token t = nextToken(); //consume OR + Token t = takeToken(); //consume OR SpelNodeImpl rhExpr = eatLogicalAndExpression(); checkOperands(t, expr, rhExpr); expr = new OpOr(toPos(t), expr, rhExpr); @@ -194,10 +201,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } // logicalAndExpression : relationalExpression (AND^ relationalExpression)*; + @Nullable private SpelNodeImpl eatLogicalAndExpression() { SpelNodeImpl expr = eatRelationalExpression(); while (peekIdentifierToken("and") || peekToken(TokenKind.SYMBOLIC_AND)) { - Token t = nextToken(); // consume 'AND' + Token t = takeToken(); // consume 'AND' SpelNodeImpl rhExpr = eatRelationalExpression(); checkOperands(t, expr, rhExpr); expr = new OpAnd(toPos(t), expr, rhExpr); @@ -206,11 +214,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } // relationalExpression : sumExpression (relationalOperator^ sumExpression)?; + @Nullable private SpelNodeImpl eatRelationalExpression() { SpelNodeImpl expr = eatSumExpression(); Token relationalOperatorToken = maybeEatRelationalOperator(); if (relationalOperatorToken != null) { - Token t = nextToken(); // consume relational operator token + Token t = takeToken(); // consume relational operator token SpelNodeImpl rhExpr = eatSumExpression(); checkOperands(t, expr, rhExpr); TokenKind tk = relationalOperatorToken.kind; @@ -251,10 +260,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } //sumExpression: productExpression ( (PLUS^ | MINUS^) productExpression)*; + @Nullable private SpelNodeImpl eatSumExpression() { SpelNodeImpl expr = eatProductExpression(); while (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.INC)) { - Token t = nextToken(); //consume PLUS or MINUS or INC + Token t = takeToken(); //consume PLUS or MINUS or INC SpelNodeImpl rhExpr = eatProductExpression(); checkRightOperand(t, rhExpr); if (t.kind == TokenKind.PLUS) { @@ -268,10 +278,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } // productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; + @Nullable private SpelNodeImpl eatProductExpression() { SpelNodeImpl expr = eatPowerIncDecExpression(); while (peekToken(TokenKind.STAR, TokenKind.DIV, TokenKind.MOD)) { - Token t = nextToken(); // consume STAR/DIV/MOD + Token t = takeToken(); // consume STAR/DIV/MOD SpelNodeImpl rhExpr = eatPowerIncDecExpression(); checkOperands(t, expr, rhExpr); if (t.kind == TokenKind.STAR) { @@ -289,16 +300,17 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } // powerExpr : unaryExpression (POWER^ unaryExpression)? (INC || DEC) ; + @Nullable private SpelNodeImpl eatPowerIncDecExpression() { SpelNodeImpl expr = eatUnaryExpression(); if (peekToken(TokenKind.POWER)) { - Token t = nextToken(); //consume POWER + Token t = takeToken(); //consume POWER SpelNodeImpl rhExpr = eatUnaryExpression(); checkRightOperand(t, rhExpr); return new OperatorPower(toPos(t), expr, rhExpr); } if (expr != null && peekToken(TokenKind.INC, TokenKind.DEC)) { - Token t = nextToken(); //consume INC/DEC + Token t = takeToken(); //consume INC/DEC if (t.getKind() == TokenKind.INC) { return new OpInc(toPos(t), true, expr); } @@ -308,10 +320,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } // unaryExpression: (PLUS^ | MINUS^ | BANG^ | INC^ | DEC^) unaryExpression | primaryExpression ; + @Nullable private SpelNodeImpl eatUnaryExpression() { if (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.NOT)) { - Token t = nextToken(); + Token t = takeToken(); SpelNodeImpl expr = eatUnaryExpression(); + Assert.state(expr != null, "No node"); if (t.kind == TokenKind.NOT) { return new OperatorNot(toPos(t), expr); } @@ -324,7 +338,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } if (peekToken(TokenKind.INC, TokenKind.DEC)) { - Token t = nextToken(); + Token t = takeToken(); SpelNodeImpl expr = eatUnaryExpression(); if (t.getKind() == TokenKind.INC) { return new OpInc(toPos(t), false, expr); @@ -346,7 +360,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { if (nodes.size() == 1) { return nodes.get(0); } - return new CompoundExpression(toPos(start.getStartPosition(), + return new CompoundExpression(toPos((start != null ? start.getStartPosition() : 0), nodes.get(nodes.size() - 1).getEndPosition()), nodes.toArray(new SpelNodeImpl[nodes.size()])); } @@ -392,7 +406,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { // ; @Nullable private SpelNodeImpl eatDottedNode() { - Token t = nextToken(); // it was a '.' or a '?.' + Token t = takeToken(); // it was a '.' or a '?.' boolean nullSafeNavigation = (t.kind == TokenKind.SAFE_NAVI); if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) { @@ -418,16 +432,16 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { if (!peekToken(TokenKind.HASH)) { return false; } - Token t = nextToken(); + Token t = takeToken(); Token functionOrVariableName = eatToken(TokenKind.IDENTIFIER); SpelNodeImpl[] args = maybeEatMethodArgs(); if (args == null) { - push(new VariableReference(functionOrVariableName.data, + push(new VariableReference(functionOrVariableName.stringValue(), toPos(t.startPos, functionOrVariableName.endPos))); return true; } - push(new FunctionReference(functionOrVariableName.data, + push(new FunctionReference(functionOrVariableName.stringValue(), toPos(t.startPos, functionOrVariableName.endPos), args)); return true; } @@ -457,11 +471,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { * Used for consuming arguments for either a method or a constructor call */ private void consumeArguments(List accumulatedArguments) { - int pos = peekToken().startPos; + Token t = peekToken(); + Assert.state(t != null, "Expected token"); + int pos = t.startPos; Token next; do { nextToken(); // consume (first time through) or comma (subsequent times) - Token t = peekToken(); + t = peekToken(); if (t == null) { raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS); } @@ -527,12 +543,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { // quoted if dotted private boolean maybeEatBeanReference() { if (peekToken(TokenKind.BEAN_REF) || peekToken(TokenKind.FACTORY_BEAN_REF)) { - Token beanRefToken = nextToken(); + Token beanRefToken = takeToken(); Token beanNameToken = null; String beanName = null; if (peekToken(TokenKind.IDENTIFIER)) { beanNameToken = eatToken(TokenKind.IDENTIFIER); - beanName = beanNameToken.data; + beanName = beanNameToken.stringValue(); } else if (peekToken(TokenKind.LITERAL_STRING)) { beanNameToken = eatToken(TokenKind.LITERAL_STRING); @@ -546,8 +562,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { BeanReference beanReference; if (beanRefToken.getKind() == TokenKind.FACTORY_BEAN_REF) { - String beanNameString = new StringBuilder(). - append(TokenKind.FACTORY_BEAN_REF.tokenChars).append(beanName).toString(); + String beanNameString = String.valueOf(TokenKind.FACTORY_BEAN_REF.tokenChars) + beanName; beanReference = new BeanReference( toPos(beanRefToken.startPos, beanNameToken.endPos), beanNameString); } @@ -563,14 +578,15 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { private boolean maybeEatTypeReference() { if (peekToken(TokenKind.IDENTIFIER)) { Token typeName = peekToken(); + Assert.state(typeName != null, "Expected token"); if (!"T".equals(typeName.stringValue())) { return false; } // It looks like a type reference but is T being used as a map key? - Token t = nextToken(); + Token t = takeToken(); if (peekToken(TokenKind.RSQUARE)) { // looks like 'T]' (T is map key) - push(new PropertyOrFieldReference(false, t.data, toPos(t))); + push(new PropertyOrFieldReference(false, t.stringValue(), toPos(t))); return true; } eatToken(TokenKind.LPAREN); @@ -592,6 +608,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { private boolean maybeEatNullReference() { if (peekToken(TokenKind.IDENTIFIER)) { Token nullToken = peekToken(); + Assert.state(nullToken != null, "Expected token"); if (!"null".equalsIgnoreCase(nullToken.stringValue())) { return false; } @@ -608,7 +625,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { if (!peekToken(TokenKind.PROJECT, true)) { return false; } + Assert.state(t != null, "No token"); SpelNodeImpl expr = eatExpression(); + Assert.state(expr != null, "No node"); eatToken(TokenKind.RSQUARE); this.constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr)); return true; @@ -621,10 +640,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { if (!peekToken(TokenKind.LCURLY, true)) { return false; } + Assert.state(t != null, "No token"); SpelNodeImpl expr = null; Token closingCurly = peekToken(); if (peekToken(TokenKind.RCURLY, true)) { // empty list '{}' + Assert.state(closingCurly != null, "No token"); expr = new InlineList(toPos(t.startPos, closingCurly.endPos)); } else if (peekToken(TokenKind.COLON, true)) { @@ -683,7 +704,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { if (!peekToken(TokenKind.LSQUARE, true)) { return false; } + Assert.state(t != null, "No token"); SpelNodeImpl expr = eatExpression(); + Assert.state(expr != null, "No node"); eatToken(TokenKind.RSQUARE); this.constructedNodes.push(new Indexer(toPos(t), expr)); return true; @@ -694,6 +717,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { if (!peekSelectToken()) { return false; } + Assert.state(t != null, "No token"); nextToken(); SpelNodeImpl expr = eatExpression(); if (expr == null) { @@ -755,16 +779,16 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { // a series of identifiers and dollars into a single identifier. private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) { if (peekToken(TokenKind.IDENTIFIER)) { - Token methodOrPropertyName = nextToken(); + Token methodOrPropertyName = takeToken(); SpelNodeImpl[] args = maybeEatMethodArgs(); if (args == null) { // property - push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data, + push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.stringValue(), toPos(methodOrPropertyName))); return true; } // method reference - push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data, + push(new MethodReference(nullSafeNavigation, methodOrPropertyName.stringValue(), toPos(methodOrPropertyName), args)); // TODO what is the end position for a method reference? the name or the last arg? return true; @@ -776,11 +800,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { //: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) private boolean maybeEatConstructorReference() { if (peekIdentifierToken("new")) { - Token newToken = nextToken(); + Token newToken = takeToken(); // It looks like a constructor reference but is NEW being used as a map key? if (peekToken(TokenKind.RSQUARE)) { // looks like 'NEW]' (so NEW used as map key) - push(new PropertyOrFieldReference(false, newToken.data, toPos(newToken))); + push(new PropertyOrFieldReference(false, newToken.stringValue(), toPos(newToken))); return true; } SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId(); @@ -839,31 +863,31 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { return false; } if (t.kind == TokenKind.LITERAL_INT) { - push(Literal.getIntLiteral(t.data, toPos(t), 10)); + push(Literal.getIntLiteral(t.stringValue(), toPos(t), 10)); } else if (t.kind == TokenKind.LITERAL_LONG) { - push(Literal.getLongLiteral(t.data, toPos(t), 10)); + push(Literal.getLongLiteral(t.stringValue(), toPos(t), 10)); } else if (t.kind == TokenKind.LITERAL_HEXINT) { - push(Literal.getIntLiteral(t.data, toPos(t), 16)); + push(Literal.getIntLiteral(t.stringValue(), toPos(t), 16)); } else if (t.kind == TokenKind.LITERAL_HEXLONG) { - push(Literal.getLongLiteral(t.data, toPos(t), 16)); + push(Literal.getLongLiteral(t.stringValue(), toPos(t), 16)); } else if (t.kind == TokenKind.LITERAL_REAL) { - push(Literal.getRealLiteral(t.data, toPos(t), false)); + push(Literal.getRealLiteral(t.stringValue(), toPos(t), false)); } else if (t.kind == TokenKind.LITERAL_REAL_FLOAT) { - push(Literal.getRealLiteral(t.data, toPos(t), true)); + push(Literal.getRealLiteral(t.stringValue(), toPos(t), true)); } else if (peekIdentifierToken("true")) { - push(new BooleanLiteral(t.data, toPos(t), true)); + push(new BooleanLiteral(t.stringValue(), toPos(t), true)); } else if (peekIdentifierToken("false")) { - push(new BooleanLiteral(t.data, toPos(t), false)); + push(new BooleanLiteral(t.stringValue(), toPos(t), false)); } else if (t.kind == TokenKind.LITERAL_STRING) { - push(new StringLiteral(t.data, toPos(t), t.data)); + push(new StringLiteral(t.stringValue(), toPos(t), t.stringValue())); } else { return false; @@ -877,6 +901,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { if (peekToken(TokenKind.LPAREN)) { nextToken(); SpelNodeImpl expr = eatExpression(); + Assert.state(expr != null, "No node"); eatToken(TokenKind.RPAREN); push(expr); return true; @@ -916,7 +941,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { private Token eatToken(TokenKind expectedKind) { Token t = nextToken(); if (t == null) { - raiseInternalException( this.expressionString.length(), SpelMessage.OOD); + int pos = this.expressionString.length(); + raiseInternalException(pos, SpelMessage.OOD); } if (t.kind != expectedKind) { raiseInternalException(t.startPos, SpelMessage.NOT_EXPECTED_TOKEN, @@ -930,10 +956,10 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } private boolean peekToken(TokenKind desiredTokenKind, boolean consumeIfMatched) { - if (!moreTokens()) { + Token t = peekToken(); + if (t == null) { return false; } - Token t = peekToken(); if (t.kind == desiredTokenKind) { if (consumeIfMatched) { this.tokenStreamPointer++; @@ -955,39 +981,42 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { } private boolean peekToken(TokenKind possible1, TokenKind possible2) { - if (!moreTokens()) { + Token t = peekToken(); + if (t == null) { return false; } - Token t = peekToken(); return (t.kind == possible1 || t.kind == possible2); } private boolean peekToken(TokenKind possible1, TokenKind possible2, TokenKind possible3) { - if (!moreTokens()) { + Token t = peekToken(); + if (t == null) { return false; } - Token t = peekToken(); return (t.kind == possible1 || t.kind == possible2 || t.kind == possible3); } private boolean peekIdentifierToken(String identifierString) { - if (!moreTokens()) { + Token t = peekToken(); + if (t == null) { return false; } - Token t = peekToken(); - return (t.kind == TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString)); + return (t.kind == TokenKind.IDENTIFIER && identifierString.equalsIgnoreCase(t.stringValue())); } private boolean peekSelectToken() { - if (!moreTokens()) { + Token t = peekToken(); + if (t == null) { return false; } - Token t = peekToken(); return (t.kind == TokenKind.SELECT || t.kind == TokenKind.SELECT_FIRST || t.kind == TokenKind.SELECT_LAST); } - private boolean moreTokens() { - return this.tokenStreamPointer= this.tokenStreamLength) { + throw new IllegalStateException("No token"); + } + return this.tokenStream.get(this.tokenStreamPointer++); } @Nullable @@ -1010,14 +1039,17 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { throw new InternalParseException(new SpelParseException(this.expressionString, pos, message, inserts)); } - public String toString(Token t) { + public String toString(@Nullable Token t) { + if (t == null) { + return ""; + } if (t.getKind().hasPayload()) { return t.stringValue(); } return t.kind.toString().toLowerCase(); } - private void checkOperands(Token token, SpelNodeImpl left, SpelNodeImpl right) { + private void checkOperands(Token token, @Nullable SpelNodeImpl left, @Nullable SpelNodeImpl right) { checkLeftOperand(token, left); checkRightOperand(token, right); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java index 9178dbbf27..40535d3cb8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java @@ -59,9 +59,11 @@ public class SpelExpression implements Expression { private final SpelParserConfiguration configuration; // The default context is used if no override is supplied by the user + @Nullable private EvaluationContext evaluationContext; // Holds the compiled form of the expression (if it has been compiled) + @Nullable private CompiledExpression compiledAst; // Count of many times as the expression been interpreted - can trigger compilation diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.java index dd1373fa8a..1317e07f16 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.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. @@ -16,6 +16,8 @@ package org.springframework.expression.spel.standard; +import org.springframework.lang.Nullable; + /** * Holder for a kind of token, the associated data and its position in the input data * stream (start/end). @@ -27,6 +29,7 @@ class Token { TokenKind kind; + @Nullable String data; int startPos; // index of first character @@ -56,18 +59,6 @@ class Token { return this.kind; } - @Override - public String toString() { - StringBuilder s = new StringBuilder(); - s.append("[").append(this.kind.toString()); - if (this.kind.hasPayload()) { - s.append(":").append(this.data); - } - s.append("]"); - s.append("(").append(this.startPos).append(",").append(this.endPos).append(")"); - return s.toString(); - } - public boolean isIdentifier() { return (this.kind == TokenKind.IDENTIFIER); } @@ -78,7 +69,7 @@ class Token { } public String stringValue() { - return this.data; + return (this.data != null ? this.data : ""); } public Token asInstanceOfToken() { @@ -93,4 +84,17 @@ class Token { return new Token(TokenKind.BETWEEN, this.startPos, this.endPos); } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("[").append(this.kind.toString()); + if (this.kind.hasPayload()) { + s.append(":").append(this.data); + } + s.append("]"); + s.append("(").append(this.startPos).append(",").append(this.endPos).append(")"); + return s.toString(); + } + } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java index d9c68c24ef..a7990c0c49 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java @@ -22,6 +22,7 @@ import org.springframework.expression.AccessException; import org.springframework.expression.ConstructorExecutor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.TypedValue; +import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; /** @@ -36,6 +37,7 @@ public class ReflectiveConstructorExecutor implements ConstructorExecutor { private final Constructor ctor; + @Nullable private final Integer varargsPosition; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java index 7703c892e7..a7f1a18451 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java @@ -37,10 +37,12 @@ public class ReflectiveMethodExecutor implements MethodExecutor { private final Method method; + @Nullable private final Integer varargsPosition; private boolean computedPublicDeclaringClass = false; + @Nullable private Class publicDeclaringClass; private boolean argumentConversionOccurred = false; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java index ba36b884b0..42c780354d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java @@ -57,6 +57,7 @@ public class ReflectiveMethodResolver implements MethodResolver { // more closely following the Java rules. private final boolean useDistance; + @Nullable private Map, MethodFilter> filters; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 848696e6ab..81dc0bf12b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -76,6 +76,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { private final Map typeDescriptorCache = new ConcurrentHashMap<>(64); + @Nullable private InvokerPair lastReadInvokerPair; @@ -122,8 +123,10 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return false; } + @Nullable public Member getLastReadInvokerPair() { - return this.lastReadInvokerPair.member; + InvokerPair lastReadInvoker = this.lastReadInvokerPair; + return (lastReadInvoker != null ? lastReadInvoker.member : null); } @Override diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java index 957c2566f5..d3f3917e75 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java @@ -49,20 +49,27 @@ import org.springframework.util.Assert; */ public class StandardEvaluationContext implements EvaluationContext { - private TypedValue rootObject; + private TypedValue rootObject = TypedValue.NULL; - private List constructorResolvers; + @Nullable + private volatile List propertyAccessors; - private List methodResolvers; + @Nullable + private volatile List constructorResolvers; + @Nullable + private volatile List methodResolvers; + + @Nullable + private volatile ReflectiveMethodResolver reflectiveMethodResolver; + + @Nullable private BeanResolver beanResolver; - private ReflectiveMethodResolver reflectiveMethodResolver; - - private List propertyAccessors; - + @Nullable private TypeLocator typeLocator; + @Nullable private TypeConverter typeConverter; private TypeComparator typeComparator = new StandardTypeComparator(); @@ -94,14 +101,21 @@ public class StandardEvaluationContext implements EvaluationContext { return this.rootObject; } - public void addConstructorResolver(ConstructorResolver resolver) { - ensureConstructorResolversInitialized(); - this.constructorResolvers.add(this.constructorResolvers.size() - 1, resolver); + public void setPropertyAccessors(List propertyAccessors) { + this.propertyAccessors = propertyAccessors; } - public boolean removeConstructorResolver(ConstructorResolver resolver) { - ensureConstructorResolversInitialized(); - return this.constructorResolvers.remove(resolver); + @Override + public List getPropertyAccessors() { + return initPropertyAccessors(); + } + + public void addPropertyAccessor(PropertyAccessor accessor) { + addBeforeDefault(initPropertyAccessors(), accessor); + } + + public boolean removePropertyAccessor(PropertyAccessor accessor) { + return initPropertyAccessors().remove(accessor); } public void setConstructorResolvers(List constructorResolvers) { @@ -110,18 +124,15 @@ public class StandardEvaluationContext implements EvaluationContext { @Override public List getConstructorResolvers() { - ensureConstructorResolversInitialized(); - return this.constructorResolvers; + return initConstructorResolvers(); } - public void addMethodResolver(MethodResolver resolver) { - ensureMethodResolversInitialized(); - this.methodResolvers.add(this.methodResolvers.size() - 1, resolver); + public void addConstructorResolver(ConstructorResolver resolver) { + addBeforeDefault(initConstructorResolvers(), resolver); } - public boolean removeMethodResolver(MethodResolver methodResolver) { - ensureMethodResolversInitialized(); - return this.methodResolvers.remove(methodResolver); + public boolean removeConstructorResolver(ConstructorResolver resolver) { + return initConstructorResolvers().remove(resolver); } public void setMethodResolvers(List methodResolvers) { @@ -130,8 +141,15 @@ public class StandardEvaluationContext implements EvaluationContext { @Override public List getMethodResolvers() { - ensureMethodResolversInitialized(); - return this.methodResolvers; + return initMethodResolvers(); + } + + public void addMethodResolver(MethodResolver resolver) { + addBeforeDefault(initMethodResolvers(), resolver); + } + + public boolean removeMethodResolver(MethodResolver methodResolver) { + return initMethodResolvers().remove(methodResolver); } public void setBeanResolver(BeanResolver beanResolver) { @@ -143,25 +161,6 @@ public class StandardEvaluationContext implements EvaluationContext { return this.beanResolver; } - public void addPropertyAccessor(PropertyAccessor accessor) { - ensurePropertyAccessorsInitialized(); - this.propertyAccessors.add(this.propertyAccessors.size() - 1, accessor); - } - - public boolean removePropertyAccessor(PropertyAccessor accessor) { - return this.propertyAccessors.remove(accessor); - } - - public void setPropertyAccessors(List propertyAccessors) { - this.propertyAccessors = propertyAccessors; - } - - @Override - public List getPropertyAccessors() { - ensurePropertyAccessorsInitialized(); - return this.propertyAccessors; - } - public void setTypeLocator(TypeLocator typeLocator) { Assert.notNull(typeLocator, "TypeLocator must not be null"); this.typeLocator = typeLocator; @@ -236,56 +235,49 @@ public class StandardEvaluationContext implements EvaluationContext { * @throws IllegalStateException if the {@link ReflectiveMethodResolver} is not in use */ public void registerMethodFilter(Class type, MethodFilter filter) throws IllegalStateException { - ensureMethodResolversInitialized(); - if (this.reflectiveMethodResolver != null) { - this.reflectiveMethodResolver.registerMethodFilter(type, filter); - } - else { - throw new IllegalStateException("Method filter cannot be set as the reflective method resolver is not in use"); + initMethodResolvers(); + ReflectiveMethodResolver resolver = this.reflectiveMethodResolver; + if (resolver == null) { + throw new IllegalStateException( + "Method filter cannot be set as the reflective method resolver is not in use"); } + resolver.registerMethodFilter(type, filter); } - private void ensurePropertyAccessorsInitialized() { - if (this.propertyAccessors == null) { - initializePropertyAccessors(); + + private List initPropertyAccessors() { + List accessors = this.propertyAccessors; + if (accessors == null) { + accessors = new ArrayList<>(5); + accessors.add(new ReflectivePropertyAccessor()); + this.propertyAccessors = accessors; } + return accessors; } - private synchronized void initializePropertyAccessors() { - if (this.propertyAccessors == null) { - List defaultAccessors = new ArrayList<>(); - defaultAccessors.add(new ReflectivePropertyAccessor()); - this.propertyAccessors = defaultAccessors; + private List initConstructorResolvers() { + List resolvers = this.constructorResolvers; + if (resolvers == null) { + resolvers = new ArrayList<>(1); + resolvers.add(new ReflectiveConstructorResolver()); + this.constructorResolvers = resolvers; } + return resolvers; } - private void ensureMethodResolversInitialized() { - if (this.methodResolvers == null) { - initializeMethodResolvers(); - } - } - - private synchronized void initializeMethodResolvers() { - if (this.methodResolvers == null) { - List defaultResolvers = new ArrayList<>(); + private List initMethodResolvers() { + List resolvers = this.methodResolvers; + if (resolvers == null) { + resolvers = new ArrayList<>(1); this.reflectiveMethodResolver = new ReflectiveMethodResolver(); - defaultResolvers.add(this.reflectiveMethodResolver); - this.methodResolvers = defaultResolvers; + resolvers.add(this.reflectiveMethodResolver); + this.methodResolvers = resolvers; } + return resolvers; } - private void ensureConstructorResolversInitialized() { - if (this.constructorResolvers == null) { - initializeConstructorResolvers(); - } - } - - private synchronized void initializeConstructorResolvers() { - if (this.constructorResolvers == null) { - List defaultResolvers = new ArrayList<>(); - defaultResolvers.add(new ReflectiveConstructorResolver()); - this.constructorResolvers = defaultResolvers; - } + private static void addBeforeDefault(List resolvers, T resolver) { + resolvers.add(resolvers.size() - 1, resolver); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java index 74a90b4fb5..1511af5baa 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java @@ -38,6 +38,7 @@ import org.springframework.util.ClassUtils; */ public class StandardTypeLocator implements TypeLocator { + @Nullable private final ClassLoader classLoader; private final List knownPackagePrefixes = new LinkedList<>(); diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java index 5a09433d9f..8f7fc88f04 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java @@ -1768,6 +1768,7 @@ public class SpelReproTests extends AbstractExpressionTests { }; } }); + result = spel.getValue(context); assertNotNull(result); assertTrue(result.getClass().isArray()); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/config/SortedResourcesFactoryBean.java b/spring-jdbc/src/main/java/org/springframework/jdbc/config/SortedResourcesFactoryBean.java index b5fe9f1243..8cd3b84803 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/config/SortedResourcesFactoryBean.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/config/SortedResourcesFactoryBean.java @@ -60,7 +60,7 @@ public class SortedResourcesFactoryBean extends AbstractFactoryBean @Override - public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { + public void setResourceLoader(ResourceLoader resourceLoader) { this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentPreparedStatementSetter.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentPreparedStatementSetter.java index 2c8bd3be97..7399eb3371 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentPreparedStatementSetter.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentPreparedStatementSetter.java @@ -29,6 +29,7 @@ import org.springframework.lang.Nullable; */ public class ArgumentPreparedStatementSetter implements PreparedStatementSetter, ParameterDisposer { + @Nullable private final Object[] args; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentTypePreparedStatementSetter.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentTypePreparedStatementSetter.java index 0b97906bbd..25fa5e3f46 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentTypePreparedStatementSetter.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ArgumentTypePreparedStatementSetter.java @@ -33,8 +33,10 @@ import org.springframework.lang.Nullable; */ public class ArgumentTypePreparedStatementSetter implements PreparedStatementSetter, ParameterDisposer { + @Nullable private final Object[] args; + @Nullable private final int[] argTypes; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java index 36dd11e963..a82a242b66 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java @@ -80,6 +80,7 @@ public class BeanPropertyRowMapper implements RowMapper { protected final Log logger = LogFactory.getLog(getClass()); /** The class we are mapping to */ + @Nullable private Class mappedClass; /** Whether we're strictly validating */ @@ -89,12 +90,15 @@ public class BeanPropertyRowMapper implements RowMapper { private boolean primitivesDefaultedForNullValue = false; /** ConversionService for binding JDBC values to bean properties */ + @Nullable private ConversionService conversionService = DefaultConversionService.getSharedInstance(); /** Map of the fields we provide mapping for */ + @Nullable private Map mappedFields; /** Set of bean properties we provide mapping for */ + @Nullable private Set mappedProperties; @@ -147,6 +151,7 @@ public class BeanPropertyRowMapper implements RowMapper { /** * Get the class that we are mapping to. */ + @Nullable public final Class getMappedClass() { return this.mappedClass; } @@ -287,7 +292,7 @@ public class BeanPropertyRowMapper implements RowMapper { for (int index = 1; index <= columnCount; index++) { String column = JdbcUtils.lookupColumnName(rsmd, index); String field = lowerCaseName(column.replaceAll(" ", "")); - PropertyDescriptor pd = this.mappedFields.get(field); + PropertyDescriptor pd = (this.mappedFields != null ? this.mappedFields.get(field) : null); if (pd != null) { try { Object value = getColumnValue(rs, index, pd); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.java index 92b40555d0..2a8deba73a 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.java @@ -121,8 +121,10 @@ public class CallableStatementCreatorFactory { */ private class CallableStatementCreatorImpl implements CallableStatementCreator, SqlProvider, ParameterDisposer { + @Nullable private ParameterMapper inParameterMapper; + @Nullable private Map inParameters; /** diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java index 72768bcbc7..c4f485c70a 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java @@ -56,7 +56,8 @@ public class PreparedStatementCreatorFactory { private boolean returnGeneratedKeys = false; - private String[] generatedKeysColumnNames = null; + @Nullable + private String[] generatedKeysColumnNames; /** diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ResultSetSupportingSqlParameter.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ResultSetSupportingSqlParameter.java index d90cc04ca5..1a72b51020 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ResultSetSupportingSqlParameter.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ResultSetSupportingSqlParameter.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. @@ -27,10 +27,13 @@ import org.springframework.lang.Nullable; */ public class ResultSetSupportingSqlParameter extends SqlParameter { + @Nullable private ResultSetExtractor resultSetExtractor; + @Nullable private RowCallbackHandler rowCallbackHandler; + @Nullable private RowMapper rowMapper; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.java index 58fb0334e0..b49a01c109 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SingleColumnRowMapper.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. @@ -43,6 +43,7 @@ import org.springframework.util.NumberUtils; */ public class SingleColumnRowMapper implements RowMapper { + @Nullable private Class requiredType; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlOutParameter.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlOutParameter.java index be78e81b24..4029b7cf08 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlOutParameter.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlOutParameter.java @@ -34,6 +34,7 @@ import org.springframework.lang.Nullable; */ public class SqlOutParameter extends ResultSetSupportingSqlParameter { + @Nullable private SqlReturnType sqlReturnType; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameter.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameter.java index 9ee4a4495a..2a6a792540 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameter.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameter.java @@ -36,15 +36,18 @@ import org.springframework.util.Assert; public class SqlParameter { /** The name of the parameter, if any */ + @Nullable private String name; /** SQL type constant from {@code java.sql.Types} */ private final int sqlType; /** Used for types that are user-named like: STRUCT, DISTINCT, JAVA_OBJECT, named array types */ + @Nullable private String typeName; /** The scale to apply in case of a NUMERIC or DECIMAL type, if any */ + @Nullable private Integer scale; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameterValue.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameterValue.java index 667131753c..0668f4c0b3 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameterValue.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlParameterValue.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. @@ -38,6 +38,7 @@ import org.springframework.lang.Nullable; */ public class SqlParameterValue extends SqlParameter { + @Nullable private final Object value; @@ -88,6 +89,7 @@ public class SqlParameterValue extends SqlParameter { /** * Return the value object that this parameter value holds. */ + @Nullable public Object getValue() { return this.value; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java index a7a65a464d..348fb5687f 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java @@ -141,8 +141,8 @@ public abstract class StatementCreatorUtils { * @param inValue the value to set * @throws SQLException if thrown by PreparedStatement methods */ - public static void setParameterValue(PreparedStatement ps, int paramIndex, SqlParameter param, Object inValue) - throws SQLException { + public static void setParameterValue(PreparedStatement ps, int paramIndex, SqlParameter param, + @Nullable Object inValue) throws SQLException { setParameterValueInternal(ps, paramIndex, param.getSqlType(), param.getTypeName(), param.getScale(), inValue); } @@ -157,8 +157,8 @@ public abstract class StatementCreatorUtils { * @throws SQLException if thrown by PreparedStatement methods * @see SqlTypeValue */ - public static void setParameterValue(PreparedStatement ps, int paramIndex, int sqlType, Object inValue) - throws SQLException { + public static void setParameterValue(PreparedStatement ps, int paramIndex, int sqlType, + @Nullable Object inValue) throws SQLException { setParameterValueInternal(ps, paramIndex, sqlType, null, null, inValue); } @@ -176,7 +176,7 @@ public abstract class StatementCreatorUtils { * @see SqlTypeValue */ public static void setParameterValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName, - Object inValue) throws SQLException { + @Nullable Object inValue) throws SQLException { setParameterValueInternal(ps, paramIndex, sqlType, typeName, null, inValue); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java index 48201f36b9..5e2bb09f36 100755 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java @@ -40,6 +40,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -56,18 +57,22 @@ public class CallMetaDataContext { protected final Log logger = LogFactory.getLog(getClass()); /** name of procedure to call **/ + @Nullable private String procedureName; /** name of catalog for call **/ + @Nullable private String catalogName; /** name of schema for call **/ + @Nullable private String schemaName; /** List of SqlParameter objects to be used in call execution */ private List callParameters = new ArrayList<>(); /** Actual name to use for the return value in the output map */ + @Nullable private String actualFunctionReturnName; /** Set of in parameter names to exclude use for any not listed */ @@ -89,6 +94,7 @@ public class CallMetaDataContext { private boolean namedBinding; /** The provider of call meta data */ + @Nullable private CallMetaDataProvider metaDataProvider; @@ -246,6 +252,7 @@ public class CallMetaDataContext { * @return the appropriate SqlParameter */ public SqlParameter createReturnResultSetParameter(String parameterName, RowMapper rowMapper) { + Assert.state(this.metaDataProvider != null, "No CallMetaDataProvider available"); if (this.metaDataProvider.isReturnResultSetSupported()) { return new SqlReturnResultSet(parameterName, rowMapper); } @@ -305,6 +312,8 @@ public class CallMetaDataContext { * Reconcile the provided parameters with available metadata and add new ones where appropriate. */ protected List reconcileParameters(List parameters) { + Assert.state(this.metaDataProvider != null, "No CallMetaDataProvider available"); + final List declaredReturnParams = new ArrayList<>(); final Map declaredParams = new LinkedHashMap<>(); boolean returnDeclared = false; @@ -464,6 +473,8 @@ public class CallMetaDataContext { * @return a Map containing the matched parameter names with the value taken from the input */ public Map matchInParameterValuesWithCallParameters(SqlParameterSource parameterSource) { + Assert.state(this.metaDataProvider != null, "No CallMetaDataProvider available"); + // For parameter source lookups we need to provide case-insensitive lookup support // since the database metadata is not necessarily providing case sensitive parameter names. Map caseInsensitiveParameterNames = @@ -527,9 +538,11 @@ public class CallMetaDataContext { * @return a Map containing the matched parameter names with the value taken from the input */ public Map matchInParameterValuesWithCallParameters(Map inParameters) { + Assert.state(this.metaDataProvider != null, "No CallMetaDataProvider available"); if (!this.metaDataProvider.isProcedureColumnMetaDataUsed()) { return inParameters; } + Map callParameterNames = new HashMap<>(this.callParameters.size()); for (SqlParameter parameter : this.callParameters) { if (parameter.isInputValueProvided()) { @@ -540,6 +553,7 @@ public class CallMetaDataContext { } } } + Map matchedParameters = new HashMap<>(inParameters.size()); for (String parameterName : inParameters.keySet()) { String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName); @@ -560,6 +574,7 @@ public class CallMetaDataContext { matchedParameters.put(callParameterName, inParameters.get(parameterName)); } } + if (matchedParameters.size() < callParameterNames.size()) { for (String parameterName : callParameterNames.keySet()) { String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName); @@ -570,6 +585,7 @@ public class CallMetaDataContext { } } } + if (logger.isDebugEnabled()) { logger.debug("Matching " + inParameters.keySet() + " with " + callParameterNames.values()); logger.debug("Found match for " + matchedParameters.keySet()); @@ -594,6 +610,8 @@ public class CallMetaDataContext { * @return the call string to be used */ public String createCallString() { + Assert.state(this.metaDataProvider != null, "No CallMetaDataProvider available"); + String callString; int parameterCount = 0; String catalogNameToUse; @@ -610,6 +628,7 @@ public class CallMetaDataContext { catalogNameToUse = this.metaDataProvider.catalogNameToUse(getCatalogName()); schemaNameToUse = this.metaDataProvider.schemaNameToUse(getSchemaName()); } + String procedureNameToUse = this.metaDataProvider.procedureNameToUse(getProcedureName()); if (isFunction() || isReturnValueRequired()) { callString = "{? = call " + @@ -624,6 +643,7 @@ public class CallMetaDataContext { (StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "") + procedureNameToUse + "("; } + for (SqlParameter parameter : this.callParameters) { if (!(parameter.isResultsParameter())) { if (parameterCount > 0) { diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallParameterMetaData.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallParameterMetaData.java index 9b293a2ad5..764fc79213 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallParameterMetaData.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallParameterMetaData.java @@ -27,12 +27,14 @@ import org.springframework.lang.Nullable; */ public class CallParameterMetaData { + @Nullable private String parameterName; private int parameterType; private int sqlType; + @Nullable private String typeName; private boolean nullable; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericTableMetaDataProvider.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericTableMetaDataProvider.java index d75a736539..e00aa84e10 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericTableMetaDataProvider.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericTableMetaDataProvider.java @@ -50,9 +50,11 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { private boolean tableColumnMetaDataUsed = false; /** the version of the database */ + @Nullable private String databaseVersion; /** the name of the user currently connected */ + @Nullable private String userName; /** indicates whether the identifiers are uppercased */ @@ -209,7 +211,6 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { logger.warn("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers': " + ex.getMessage()); } } - } @Override @@ -284,6 +285,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { /** * Provide access to default schema for subclasses. */ + @Nullable protected String getDefaultSchema() { return this.userName; } @@ -291,6 +293,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { /** * Provide access to version info for subclasses. */ + @Nullable protected String getDatabaseVersion() { return this.databaseVersion; } @@ -427,10 +430,13 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { */ private static class TableMetaData { + @Nullable private String catalogName; + @Nullable private String schemaName; + @Nullable private String tableName; public void setCatalogName(String catalogName) { diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/OracleTableMetaDataProvider.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/OracleTableMetaDataProvider.java index 93ebbba666..6f20d85c73 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/OracleTableMetaDataProvider.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/OracleTableMetaDataProvider.java @@ -43,6 +43,7 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider { private final boolean includeSynonyms; + @Nullable private String defaultSchema; @@ -104,7 +105,8 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider { @Override public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, - @Nullable String catalogName, @Nullable String schemaName, String tableName) throws SQLException { + @Nullable String catalogName, @Nullable String schemaName, @Nullable String tableName) + throws SQLException { if (!this.includeSynonyms) { logger.debug("Defaulting to no synonyms in table metadata lookup"); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/PostgresTableMetaDataProvider.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/PostgresTableMetaDataProvider.java index da5cc30f18..07ea891e6f 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/PostgresTableMetaDataProvider.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/PostgresTableMetaDataProvider.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. @@ -35,13 +35,14 @@ public class PostgresTableMetaDataProvider extends GenericTableMetaDataProvider @Override public boolean isGetGeneratedKeysSimulated() { - if (getDatabaseVersion().compareTo("8.2.0") >= 0) { + String version = getDatabaseVersion(); + if (version != null && version.compareTo("8.2.0") >= 0) { return true; } else { if (logger.isWarnEnabled()) { logger.warn("PostgreSQL does not support getGeneratedKeys or INSERT ... RETURNING in version " + - getDatabaseVersion()); + version); } return false; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSource.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSource.java index 50cb90632e..5c3bc9ad5b 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSource.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/BeanPropertySqlParameterSource.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.springframework.beans.NotReadablePropertyException; import org.springframework.beans.PropertyAccessor; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.jdbc.core.StatementCreatorUtils; +import org.springframework.lang.Nullable; /** * {@link SqlParameterSource} implementation that obtains parameter values @@ -43,6 +44,7 @@ public class BeanPropertySqlParameterSource extends AbstractSqlParameterSource { private final BeanWrapper beanWrapper; + @Nullable private String[] propertyNames; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcDaoSupport.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcDaoSupport.java index c4ae1b4eef..7ff8d0f102 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcDaoSupport.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcDaoSupport.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,7 +16,9 @@ package org.springframework.jdbc.core.namedparam; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.support.JdbcDaoSupport; +import org.springframework.lang.Nullable; /** * Extension of JdbcDaoSupport that exposes a NamedParameterJdbcTemplate as well. @@ -28,6 +30,7 @@ import org.springframework.jdbc.core.support.JdbcDaoSupport; */ public class NamedParameterJdbcDaoSupport extends JdbcDaoSupport { + @Nullable private NamedParameterJdbcTemplate namedParameterJdbcTemplate; @@ -36,14 +39,18 @@ public class NamedParameterJdbcDaoSupport extends JdbcDaoSupport { */ @Override protected void initTemplateConfig() { - this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(getJdbcTemplate()); + JdbcTemplate jdbcTemplate = getJdbcTemplate(); + if (jdbcTemplate != null) { + this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate); + } } /** * Return a NamedParameterJdbcTemplate wrapping the configured JdbcTemplate. */ + @Nullable public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() { - return namedParameterJdbcTemplate; + return this.namedParameterJdbcTemplate; } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/JdbcDaoSupport.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/JdbcDaoSupport.java index d034db460f..886cc6b3e5 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/JdbcDaoSupport.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/JdbcDaoSupport.java @@ -24,6 +24,7 @@ import org.springframework.jdbc.CannotGetJdbcConnectionException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.jdbc.support.SQLExceptionTranslator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -45,6 +46,7 @@ import org.springframework.util.Assert; */ public abstract class JdbcDaoSupport extends DaoSupport { + @Nullable private JdbcTemplate jdbcTemplate; @@ -91,6 +93,7 @@ public abstract class JdbcDaoSupport extends DaoSupport { * Return the JdbcTemplate for this DAO, * pre-initialized with the DataSource or set explicitly. */ + @Nullable public final JdbcTemplate getJdbcTemplate() { return this.jdbcTemplate; } @@ -120,7 +123,9 @@ public abstract class JdbcDaoSupport extends DaoSupport { * @see org.springframework.jdbc.core.JdbcTemplate#getExceptionTranslator() */ protected final SQLExceptionTranslator getExceptionTranslator() { - return getJdbcTemplate().getExceptionTranslator(); + JdbcTemplate jdbcTemplate = getJdbcTemplate(); + Assert.state(jdbcTemplate != null, "No JdbcTemplate set"); + return jdbcTemplate.getExceptionTranslator(); } /** diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/SqlLobValue.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/SqlLobValue.java index 98fb589792..711339eb01 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/SqlLobValue.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/support/SqlLobValue.java @@ -66,6 +66,7 @@ import org.springframework.lang.Nullable; */ public class SqlLobValue implements DisposableSqlTypeValue { + @Nullable private final Object content; private final int length; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/AbstractDriverBasedDataSource.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/AbstractDriverBasedDataSource.java index 61ae956df9..25e32f114f 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/AbstractDriverBasedDataSource.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/AbstractDriverBasedDataSource.java @@ -34,16 +34,22 @@ import org.springframework.util.Assert; */ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource { + @Nullable private String url; + @Nullable private String username; + @Nullable private String password; + @Nullable private String catalog; + @Nullable private String schema; + @Nullable private Properties connectionProperties; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionHolder.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionHolder.java index 82bfe63e93..95e8909bc0 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionHolder.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionHolder.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. @@ -44,12 +44,15 @@ public class ConnectionHolder extends ResourceHolderSupport { public static final String SAVEPOINT_NAME_PREFIX = "SAVEPOINT_"; + @Nullable private ConnectionHandle connectionHandle; + @Nullable private Connection currentConnection; private boolean transactionActive = false; + @Nullable private Boolean savepointsSupported; private int savepointCounter = 0; @@ -93,6 +96,7 @@ public class ConnectionHolder extends ResourceHolderSupport { /** * Return the ConnectionHandle held by this ConnectionHolder. */ + @Nullable public ConnectionHandle getConnectionHandle() { return this.connectionHandle; } @@ -128,7 +132,9 @@ public class ConnectionHolder extends ResourceHolderSupport { */ protected void setConnection(@Nullable Connection connection) { if (this.currentConnection != null) { - this.connectionHandle.releaseConnection(this.currentConnection); + if (this.connectionHandle != null) { + this.connectionHandle.releaseConnection(this.currentConnection); + } this.currentConnection = null; } if (connection != null) { @@ -189,7 +195,9 @@ public class ConnectionHolder extends ResourceHolderSupport { public void released() { super.released(); if (!isOpen() && this.currentConnection != null) { - this.connectionHandle.releaseConnection(this.currentConnection); + if (this.connectionHandle != null) { + this.connectionHandle.releaseConnection(this.currentConnection); + } this.currentConnection = null; } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java index cb362c1b17..9ccdce84c9 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java @@ -112,6 +112,7 @@ import org.springframework.util.Assert; public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean { + @Nullable private DataSource dataSource; private boolean enforceReadOnly = false; @@ -236,7 +237,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan DataSourceTransactionObject txObject = new DataSourceTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed()); ConnectionHolder conHolder = - (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource); + (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource()); txObject.setConnectionHolder(conHolder, false); return txObject; } @@ -298,7 +299,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan catch (Throwable ex) { if (txObject.isNewConnectionHolder()) { - DataSourceUtils.releaseConnection(con, this.dataSource); + DataSourceUtils.releaseConnection(con, obtainDataSource()); txObject.setConnectionHolder(null, false); } throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex); @@ -309,12 +310,12 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan protected Object doSuspend(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; txObject.setConnectionHolder(null); - return TransactionSynchronizationManager.unbindResource(this.dataSource); + return TransactionSynchronizationManager.unbindResource(obtainDataSource()); } @Override protected void doResume(@Nullable Object transaction, Object suspendedResources) { - TransactionSynchronizationManager.bindResource(this.dataSource, suspendedResources); + TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources); } @Override @@ -363,7 +364,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan // Remove the connection holder from the thread, if exposed. if (txObject.isNewConnectionHolder()) { - TransactionSynchronizationManager.unbindResource(this.dataSource); + TransactionSynchronizationManager.unbindResource(obtainDataSource()); } // Reset connection. diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/IsolationLevelDataSourceAdapter.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/IsolationLevelDataSourceAdapter.java index 59fa23a02f..fd9e9e10c4 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/IsolationLevelDataSourceAdapter.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/IsolationLevelDataSourceAdapter.java @@ -58,6 +58,7 @@ public class IsolationLevelDataSourceAdapter extends UserCredentialsDataSourceAd /** Constants instance for TransactionDefinition */ private static final Constants constants = new Constants(TransactionDefinition.class); + @Nullable private Integer isolationLevel; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java index 6741576485..09c672c78e 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/JdbcTransactionObjectSupport.java @@ -51,8 +51,10 @@ public abstract class JdbcTransactionObjectSupport implements SavepointManager, private static final Log logger = LogFactory.getLog(JdbcTransactionObjectSupport.class); + @Nullable private ConnectionHolder connectionHolder; + @Nullable private Integer previousIsolationLevel; private boolean savepointAllowed = false; @@ -75,6 +77,7 @@ public abstract class JdbcTransactionObjectSupport implements SavepointManager, this.previousIsolationLevel = previousIsolationLevel; } + @Nullable public Integer getPreviousIsolationLevel() { return this.previousIsolationLevel; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java index 390e3fa9d2..2ea6c3f07c 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java @@ -83,8 +83,10 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource { private static final Log logger = LogFactory.getLog(LazyConnectionDataSourceProxy.class); + @Nullable private Boolean defaultAutoCommit; + @Nullable private Integer defaultTransactionIsolation; @@ -193,6 +195,7 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource { /** * Expose the default auto-commit value. */ + @Nullable protected Boolean defaultAutoCommit() { return this.defaultAutoCommit; } @@ -200,6 +203,7 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource { /** * Expose the default transaction isolation value. */ + @Nullable protected Integer defaultTransactionIsolation() { return this.defaultTransactionIsolation; } @@ -246,18 +250,23 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource { */ private class LazyConnectionInvocationHandler implements InvocationHandler { + @Nullable private String username; + @Nullable private String password; private Boolean readOnly = Boolean.FALSE; - private Integer transactionIsolation; - + @Nullable private Boolean autoCommit; + @Nullable + private Integer transactionIsolation; + private boolean closed = false; + @Nullable private Connection target; public LazyConnectionInvocationHandler() { diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/SingleConnectionDataSource.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/SingleConnectionDataSource.java index 7cbc190883..52657101b0 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/SingleConnectionDataSource.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/SingleConnectionDataSource.java @@ -58,12 +58,15 @@ public class SingleConnectionDataSource extends DriverManagerDataSource implemen private boolean suppressClose; /** Override auto-commit state? */ + @Nullable private Boolean autoCommit; /** Wrapped Connection */ + @Nullable private Connection target; /** Proxy Connection */ + @Nullable private Connection connection; /** Synchronization monitor for the shared Connection */ diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy.java index e529b82f0a..0a560a5271 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy.java @@ -160,6 +160,7 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource { private final DataSource targetDataSource; + @Nullable private Connection target; private boolean closed = false; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapter.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapter.java index 65bfe395ba..8e7f58c88b 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapter.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/UserCredentialsDataSourceAdapter.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,6 +20,7 @@ import java.sql.Connection; import java.sql.SQLException; import org.springframework.core.NamedThreadLocal; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -61,12 +62,16 @@ import org.springframework.util.StringUtils; */ public class UserCredentialsDataSourceAdapter extends DelegatingDataSource { + @Nullable private String username; + @Nullable private String password; + @Nullable private String catalog; + @Nullable private String schema; private final ThreadLocal threadBoundCredentials = @@ -183,7 +188,7 @@ public class UserCredentialsDataSourceAdapter extends DelegatingDataSource { * @see javax.sql.DataSource#getConnection(String, String) * @see javax.sql.DataSource#getConnection() */ - protected Connection doGetConnection(String username, String password) throws SQLException { + protected Connection doGetConnection(@Nullable String username, @Nullable String password) throws SQLException { Assert.state(getTargetDataSource() != null, "'targetDataSource' is required"); if (StringUtils.hasLength(username)) { return getTargetDataSource().getConnection(username, password); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/DerbyEmbeddedDatabaseConfigurer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/DerbyEmbeddedDatabaseConfigurer.java index 9c0a0a196a..081218e967 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/DerbyEmbeddedDatabaseConfigurer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/DerbyEmbeddedDatabaseConfigurer.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. @@ -23,6 +23,8 @@ import javax.sql.DataSource; import org.apache.commons.logging.LogFactory; import org.apache.derby.jdbc.EmbeddedDriver; +import org.springframework.lang.Nullable; + /** * {@link EmbeddedDatabaseConfigurer} for the Apache Derby database 10.6+. *

Call {@link #getInstance()} to get the singleton instance of this class. @@ -35,6 +37,7 @@ final class DerbyEmbeddedDatabaseConfigurer implements EmbeddedDatabaseConfigure private static final String URL_TEMPLATE = "jdbc:derby:memory:%s;%s"; + @Nullable private static DerbyEmbeddedDatabaseConfigurer instance; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java index 899029885d..0196a4bec0 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.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. @@ -21,7 +21,6 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.UUID; import java.util.logging.Logger; - import javax.sql.DataSource; import org.apache.commons.logging.Log; @@ -77,10 +76,13 @@ public class EmbeddedDatabaseFactory { private DataSourceFactory dataSourceFactory = new SimpleDriverDataSourceFactory(); + @Nullable private EmbeddedDatabaseConfigurer databaseConfigurer; + @Nullable private DatabasePopulator databasePopulator; + @Nullable private DataSource dataSource; @@ -222,7 +224,9 @@ public class EmbeddedDatabaseFactory { logger.info(String.format("Shutting down embedded database '%s'", this.databaseName)); } } - this.databaseConfigurer.shutdown(this.dataSource, this.databaseName); + if (this.databaseConfigurer != null) { + this.databaseConfigurer.shutdown(this.dataSource, this.databaseName); + } this.dataSource = null; } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBean.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBean.java index ba4f1e9eec..d754f435f2 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBean.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactoryBean.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.jdbc.datasource.init.DatabasePopulator; import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; +import org.springframework.lang.Nullable; /** * A subclass of {@link EmbeddedDatabaseFactory} that implements {@link FactoryBean} @@ -43,6 +44,7 @@ import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; public class EmbeddedDatabaseFactoryBean extends EmbeddedDatabaseFactory implements FactoryBean, InitializingBean, DisposableBean { + @Nullable private DatabasePopulator databaseCleaner; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/H2EmbeddedDatabaseConfigurer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/H2EmbeddedDatabaseConfigurer.java index 57c6000a6d..540bbf7233 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/H2EmbeddedDatabaseConfigurer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/H2EmbeddedDatabaseConfigurer.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. @@ -18,6 +18,7 @@ package org.springframework.jdbc.datasource.embedded; import java.sql.Driver; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -31,6 +32,7 @@ import org.springframework.util.ClassUtils; */ final class H2EmbeddedDatabaseConfigurer extends AbstractEmbeddedDatabaseConfigurer { + @Nullable private static H2EmbeddedDatabaseConfigurer instance; private final Class driverClass; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/HsqlEmbeddedDatabaseConfigurer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/HsqlEmbeddedDatabaseConfigurer.java index 89f37f2d3d..acf8d61ecb 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/HsqlEmbeddedDatabaseConfigurer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/HsqlEmbeddedDatabaseConfigurer.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. @@ -18,6 +18,7 @@ package org.springframework.jdbc.datasource.embedded; import java.sql.Driver; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -30,6 +31,7 @@ import org.springframework.util.ClassUtils; */ final class HsqlEmbeddedDatabaseConfigurer extends AbstractEmbeddedDatabaseConfigurer { + @Nullable private static HsqlEmbeddedDatabaseConfigurer instance; private final Class driverClass; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java index c783f77f1c..5d68d15d03 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java @@ -35,6 +35,7 @@ import org.springframework.util.Assert; */ public class DataSourceInitializer implements InitializingBean, DisposableBean { + @Nullable private DataSource dataSource; private DatabasePopulator databasePopulator; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java index 192fd96e83..213c033a3e 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.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.sql.Connection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import javax.sql.DataSource; import org.springframework.core.io.Resource; @@ -56,6 +55,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator { List scripts = new ArrayList<>(); + @Nullable private String sqlScriptEncoding; private String separator = ScriptUtils.DEFAULT_STATEMENT_SEPARATOR; @@ -155,7 +155,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator { * @see #addScript(Resource) */ public void setSqlScriptEncoding(@Nullable String sqlScriptEncoding) { - this.sqlScriptEncoding = StringUtils.hasText(sqlScriptEncoding) ? sqlScriptEncoding : null; + this.sqlScriptEncoding = (StringUtils.hasText(sqlScriptEncoding) ? sqlScriptEncoding : null); } /** diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.java index f0983a3bd3..6508e0211f 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.java @@ -40,16 +40,20 @@ import org.springframework.util.Assert; */ public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean { + @Nullable private Map targetDataSources; + @Nullable private Object defaultTargetDataSource; private boolean lenientFallback = true; private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); + @Nullable private Map resolvedDataSources; + @Nullable private DataSource resolvedDefaultDataSource; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookup.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookup.java index f4dbbaf5a2..5a770c70c9 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookup.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/lookup/BeanFactoryDataSourceLookup.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.sql.DataSource; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -36,6 +37,7 @@ import org.springframework.util.Assert; */ public class BeanFactoryDataSourceLookup implements DataSourceLookup, BeanFactoryAware { + @Nullable private BeanFactory beanFactory; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java b/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java index 7ad16f8557..99604cab81 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/object/GenericSqlQuery.java @@ -35,9 +35,11 @@ import org.springframework.util.Assert; */ public class GenericSqlQuery extends SqlQuery { + @Nullable private RowMapper rowMapper; @SuppressWarnings("rawtypes") + @Nullable private Class rowMapperClass; @@ -69,7 +71,13 @@ public class GenericSqlQuery extends SqlQuery { @Override @SuppressWarnings("unchecked") protected RowMapper newRowMapper(@Nullable Object[] parameters, @Nullable Map context) { - return (this.rowMapper != null ? this.rowMapper : BeanUtils.instantiateClass(this.rowMapperClass)); + if (this.rowMapper != null) { + return this.rowMapper; + } + else { + Assert.state(this.rowMapperClass != null, "No RowMapper set"); + return BeanUtils.instantiateClass(this.rowMapperClass); + } } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/object/MappingSqlQueryWithParameters.java b/spring-jdbc/src/main/java/org/springframework/jdbc/object/MappingSqlQueryWithParameters.java index 8cfc54c1fb..e862042f2d 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/object/MappingSqlQueryWithParameters.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/object/MappingSqlQueryWithParameters.java @@ -102,8 +102,10 @@ public abstract class MappingSqlQueryWithParameters extends SqlQuery { */ protected class RowMapperImpl implements RowMapper { + @Nullable private final Object[] params; + @Nullable private final Map context; /** diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/object/RdbmsOperation.java b/spring-jdbc/src/main/java/org/springframework/jdbc/object/RdbmsOperation.java index 7e5a697410..bec9ee5758 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/object/RdbmsOperation.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/object/RdbmsOperation.java @@ -72,8 +72,10 @@ public abstract class RdbmsOperation implements InitializingBean { private boolean returnGeneratedKeys = false; - private String[] generatedKeysColumnNames = null; + @Nullable + private String[] generatedKeysColumnNames; + @Nullable private String sql; private final List declaredParameters = new LinkedList<>(); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlCall.java b/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlCall.java index 3196499910..4b72fce613 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlCall.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlCall.java @@ -18,7 +18,6 @@ package org.springframework.jdbc.object; import java.util.List; import java.util.Map; - import javax.sql.DataSource; import org.springframework.jdbc.core.CallableStatementCreator; @@ -26,6 +25,7 @@ import org.springframework.jdbc.core.CallableStatementCreatorFactory; import org.springframework.jdbc.core.ParameterMapper; import org.springframework.jdbc.core.SqlParameter; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * RdbmsOperation using a JdbcTemplate and representing a SQL-based @@ -44,6 +44,7 @@ public abstract class SqlCall extends RdbmsOperation { * Object enabling us to create CallableStatementCreators * efficiently, based on this class's declared parameters. */ + @Nullable private CallableStatementCreatorFactory callableStatementFactory; /** @@ -64,6 +65,7 @@ public abstract class SqlCall extends RdbmsOperation { * or {? = call get_invoice_count(?)} if isFunction is set to true * Updated after each parameter is added. */ + @Nullable private String callString; @@ -153,10 +155,10 @@ public abstract class SqlCall extends RdbmsOperation { this.callString += ")}"; } if (logger.isDebugEnabled()) { - logger.debug("Compiled stored procedure. Call string is [" + getCallString() + "]"); + logger.debug("Compiled stored procedure. Call string is [" + this.callString + "]"); } - this.callableStatementFactory = new CallableStatementCreatorFactory(getCallString(), getDeclaredParameters()); + this.callableStatementFactory = new CallableStatementCreatorFactory(this.callString, getDeclaredParameters()); this.callableStatementFactory.setResultSetType(getResultSetType()); this.callableStatementFactory.setUpdatableResults(isUpdatableResults()); @@ -173,6 +175,7 @@ public abstract class SqlCall extends RdbmsOperation { /** * Get the call string. */ + @Nullable public String getCallString() { return this.callString; } @@ -183,6 +186,7 @@ public abstract class SqlCall extends RdbmsOperation { * @param inParams parameters. May be {@code null}. */ protected CallableStatementCreator newCallableStatementCreator(@Nullable Map inParams) { + Assert.state(this.callableStatementFactory != null, "No CallableStatementFactory available"); return this.callableStatementFactory.newCallableStatementCreator(inParams); } @@ -192,6 +196,7 @@ public abstract class SqlCall extends RdbmsOperation { * @param inParamMapper parametermapper. May not be {@code null}. */ protected CallableStatementCreator newCallableStatementCreator(ParameterMapper inParamMapper) { + Assert.state(this.callableStatementFactory != null, "No CallableStatementFactory available"); return this.callableStatementFactory.newCallableStatementCreator(inParamMapper); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlOperation.java b/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlOperation.java index 07075c0014..a694118800 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlOperation.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/object/SqlOperation.java @@ -22,6 +22,7 @@ import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.namedparam.NamedParameterUtils; import org.springframework.jdbc.core.namedparam.ParsedSql; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Operation object representing a SQL-based operation such as a query or update, @@ -39,9 +40,11 @@ public abstract class SqlOperation extends RdbmsOperation { * Object enabling us to create PreparedStatementCreators efficiently, * based on this class's declared parameters. */ + @Nullable private PreparedStatementCreatorFactory preparedStatementFactory; /** Parsed representation of the SQL statement */ + @Nullable private ParsedSql cachedSql; /** Monitor for locking the cached representation of the parsed SQL statement */ @@ -93,6 +96,7 @@ public abstract class SqlOperation extends RdbmsOperation { * @param params the parameter array (may be {@code null}) */ protected final PreparedStatementSetter newPreparedStatementSetter(@Nullable Object[] params) { + Assert.state(this.preparedStatementFactory != null, "No PreparedStatementFactory available"); return this.preparedStatementFactory.newPreparedStatementSetter(params); } @@ -102,6 +106,7 @@ public abstract class SqlOperation extends RdbmsOperation { * @param params the parameter array (may be {@code null}) */ protected final PreparedStatementCreator newPreparedStatementCreator(@Nullable Object[] params) { + Assert.state(this.preparedStatementFactory != null, "No PreparedStatementFactory available"); return this.preparedStatementFactory.newPreparedStatementCreator(params); } @@ -113,6 +118,7 @@ public abstract class SqlOperation extends RdbmsOperation { * @param params the parameter array (may be {@code null}) */ protected final PreparedStatementCreator newPreparedStatementCreator(String sqlToUse, @Nullable Object[] params) { + Assert.state(this.preparedStatementFactory != null, "No PreparedStatementFactory available"); return this.preparedStatementFactory.newPreparedStatementCreator(sqlToUse, params); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/object/UpdatableSqlQuery.java b/spring-jdbc/src/main/java/org/springframework/jdbc/object/UpdatableSqlQuery.java index 33a063a5be..e064f80144 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/object/UpdatableSqlQuery.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/object/UpdatableSqlQuery.java @@ -19,7 +19,6 @@ package org.springframework.jdbc.object; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Map; - import javax.sql.DataSource; import org.springframework.jdbc.core.RowMapper; @@ -89,6 +88,7 @@ public abstract class UpdatableSqlQuery extends SqlQuery { */ protected class RowMapperImpl implements RowMapper { + @Nullable private final Map context; public RowMapperImpl(@Nullable Map context) { diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java index 070f41a728..a07b328cb8 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.jdbc.CannotGetJdbcConnectionException; +import org.springframework.lang.Nullable; /** * Bean that checks if a database has already started up. To be referenced @@ -47,8 +48,10 @@ public class DatabaseStartupValidator implements InitializingBean { protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private DataSource dataSource; + @Nullable private String validationQuery; private int interval = DEFAULT_INTERVAL; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcAccessor.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcAccessor.java index 12178ccc39..e1a65855f9 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcAccessor.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcAccessor.java @@ -42,8 +42,10 @@ public abstract class JdbcAccessor implements InitializingBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private DataSource dataSource; + @Nullable private SQLExceptionTranslator exceptionTranslator; private boolean lazyInit = true; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java index ae0005c8fd..2a557487dd 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java @@ -74,6 +74,7 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep /** Error codes used by this translator */ + @Nullable private SQLErrorCodes sqlErrorCodes; @@ -160,6 +161,7 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep * Usually determined via a DataSource. * @see #setDataSource */ + @Nullable public SQLErrorCodes getSqlErrorCodes() { return this.sqlErrorCodes; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java index 2afb3c5b97..72f261b9df 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java @@ -35,6 +35,7 @@ import org.springframework.util.StringUtils; */ public class SQLErrorCodes { + @Nullable private String[] databaseProductNames; private boolean useSqlStateForTranslation = false; @@ -59,8 +60,10 @@ public class SQLErrorCodes { private String[] cannotSerializeTransactionCodes = new String[0]; + @Nullable private CustomSQLErrorCodesTranslation[] customTranslations; + @Nullable private SQLExceptionTranslator customSqlExceptionTranslator; @@ -86,6 +89,7 @@ public class SQLErrorCodes { this.databaseProductNames = databaseProductNames; } + @Nullable public String[] getDatabaseProductNames() { return this.databaseProductNames; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughBlob.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughBlob.java index d55a0fd5c2..900174f84a 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughBlob.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughBlob.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. @@ -22,6 +22,9 @@ import java.io.OutputStream; import java.sql.Blob; import java.sql.SQLException; +import org.springframework.lang.Nullable; +import org.springframework.util.StreamUtils; + /** * Simple JDBC {@link Blob} adapter that exposes a given byte array or binary stream. * Optionally used by {@link DefaultLobHandler}. @@ -31,8 +34,10 @@ import java.sql.SQLException; */ class PassThroughBlob implements Blob { + @Nullable private byte[] content; + @Nullable private InputStream binaryStream; private long contentLength; @@ -56,7 +61,12 @@ class PassThroughBlob implements Blob { @Override public InputStream getBinaryStream() throws SQLException { - return (this.content != null ? new ByteArrayInputStream(this.content) : this.binaryStream); + if (this.content != null) { + return new ByteArrayInputStream(this.content); + } + else { + return (this.binaryStream != null ? this.binaryStream : StreamUtils.emptyInput()); + } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughClob.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughClob.java index 882085c946..655cf620b5 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughClob.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/PassThroughClob.java @@ -28,7 +28,9 @@ import java.nio.charset.StandardCharsets; import java.sql.Clob; import java.sql.SQLException; +import org.springframework.lang.Nullable; import org.springframework.util.FileCopyUtils; +import org.springframework.util.StreamUtils; /** * Simple JDBC {@link Clob} adapter that exposes a given String or character stream. @@ -39,10 +41,13 @@ import org.springframework.util.FileCopyUtils; */ class PassThroughClob implements Clob { + @Nullable private String content; + @Nullable private Reader characterStream; + @Nullable private InputStream asciiStream; private long contentLength; @@ -78,7 +83,9 @@ class PassThroughClob implements Clob { return this.characterStream; } else { - return new InputStreamReader(this.asciiStream, StandardCharsets.US_ASCII); + return new InputStreamReader( + (this.asciiStream != null ? this.asciiStream : StreamUtils.emptyInput()), + StandardCharsets.US_ASCII); } } @@ -93,7 +100,7 @@ class PassThroughClob implements Clob { return new ByteArrayInputStream(tempContent.getBytes(StandardCharsets.US_ASCII)); } else { - return this.asciiStream; + return (this.asciiStream != null ? this.asciiStream : StreamUtils.emptyInput()); } } catch (IOException ex) { diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/rowset/ResultSetWrappingSqlRowSetMetaData.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/rowset/ResultSetWrappingSqlRowSetMetaData.java index 50f0369551..88e5f54865 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/rowset/ResultSetWrappingSqlRowSetMetaData.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/rowset/ResultSetWrappingSqlRowSetMetaData.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,6 +20,7 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import org.springframework.jdbc.InvalidResultSetAccessException; +import org.springframework.lang.Nullable; /** * The default implementation of Spring's {@link SqlRowSetMetaData} interface, wrapping @@ -37,6 +38,7 @@ public class ResultSetWrappingSqlRowSetMetaData implements SqlRowSetMetaData { private final ResultSetMetaData resultSetMetaData; + @Nullable private String[] columnNames; diff --git a/spring-jms/src/main/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessor.java b/spring-jms/src/main/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessor.java index 0ca4e8c63d..896874fb83 100644 --- a/spring-jms/src/main/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessor.java +++ b/spring-jms/src/main/java/org/springframework/jms/annotation/JmsListenerAnnotationBeanPostProcessor.java @@ -93,15 +93,19 @@ public class JmsListenerAnnotationBeanPostProcessor protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private JmsListenerEndpointRegistry endpointRegistry; + @Nullable private String containerFactoryBeanName = DEFAULT_JMS_LISTENER_CONTAINER_FACTORY_BEAN_NAME; private final MessageHandlerMethodFactoryAdapter messageHandlerMethodFactory = new MessageHandlerMethodFactoryAdapter(); + @Nullable private BeanFactory beanFactory; + @Nullable private StringValueResolver embeddedValueResolver; private final JmsListenerEndpointRegistrar registrar = new JmsListenerEndpointRegistrar(); @@ -296,10 +300,10 @@ public class JmsListenerAnnotationBeanPostProcessor return new MethodJmsListenerEndpoint(); } - @Nullable private String getEndpointId(JmsListener jmsListener) { if (StringUtils.hasText(jmsListener.id())) { - return resolve(jmsListener.id()); + String id = resolve(jmsListener.id()); + return (id != null ? id : ""); } else { return "org.springframework.jms.JmsListenerEndpointContainer#" + this.counter.getAndIncrement(); @@ -320,6 +324,7 @@ public class JmsListenerAnnotationBeanPostProcessor */ private class MessageHandlerMethodFactoryAdapter implements MessageHandlerMethodFactory { + @Nullable private MessageHandlerMethodFactory messageHandlerMethodFactory; public void setMessageHandlerMethodFactory(MessageHandlerMethodFactory messageHandlerMethodFactory) { diff --git a/spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java b/spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java index a49946804f..67987f0788 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java @@ -25,6 +25,7 @@ import org.springframework.jms.listener.AbstractMessageListenerContainer; import org.springframework.jms.support.QosSettings; import org.springframework.jms.support.converter.MessageConverter; import org.springframework.jms.support.destination.DestinationResolver; +import org.springframework.lang.Nullable; import org.springframework.util.ErrorHandler; /** @@ -39,32 +40,46 @@ public abstract class AbstractJmsListenerContainerFactory { + @Nullable private ResourceAdapter resourceAdapter; + @Nullable private JmsActivationSpecFactory activationSpecFactory; + @Nullable private DestinationResolver destinationResolver; + @Nullable private Object transactionManager; + @Nullable private Integer phase; diff --git a/spring-jms/src/main/java/org/springframework/jms/config/DefaultJmsListenerContainerFactory.java b/spring-jms/src/main/java/org/springframework/jms/config/DefaultJmsListenerContainerFactory.java index 26959cc321..f1f4e488cc 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/DefaultJmsListenerContainerFactory.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/DefaultJmsListenerContainerFactory.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. @@ -19,6 +19,7 @@ package org.springframework.jms.config; import java.util.concurrent.Executor; import org.springframework.jms.listener.DefaultMessageListenerContainer; +import org.springframework.lang.Nullable; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.util.backoff.BackOff; @@ -35,22 +36,31 @@ import org.springframework.util.backoff.BackOff; public class DefaultJmsListenerContainerFactory extends AbstractJmsListenerContainerFactory { + @Nullable private Executor taskExecutor; + @Nullable private PlatformTransactionManager transactionManager; + @Nullable private Integer cacheLevel; + @Nullable private String cacheLevelName; + @Nullable private String concurrency; + @Nullable private Integer maxMessagesPerTask; + @Nullable private Long receiveTimeout; + @Nullable private Long recoveryInterval; + @Nullable private BackOff backOff; diff --git a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistrar.java b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistrar.java index d0cb7d818d..703f284bd2 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistrar.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistrar.java @@ -38,14 +38,19 @@ import org.springframework.util.Assert; */ public class JmsListenerEndpointRegistrar implements BeanFactoryAware, InitializingBean { + @Nullable private JmsListenerEndpointRegistry endpointRegistry; + @Nullable private MessageHandlerMethodFactory messageHandlerMethodFactory; + @Nullable private JmsListenerContainerFactory containerFactory; + @Nullable private String containerFactoryBeanName; + @Nullable private BeanFactory beanFactory; private final List endpointDescriptors = new ArrayList<>(); @@ -131,6 +136,7 @@ public class JmsListenerEndpointRegistrar implements BeanFactoryAware, Initializ } protected void registerAllEndpoints() { + Assert.state(this.endpointRegistry != null, "No JmsListenerEndpointRegistry set"); synchronized (this.mutex) { for (JmsListenerEndpointDescriptor descriptor : this.endpointDescriptors) { this.endpointRegistry.registerListenerContainer( @@ -168,7 +174,7 @@ public class JmsListenerEndpointRegistrar implements BeanFactoryAware, Initializ * used for that endpoint. */ public void registerEndpoint(JmsListenerEndpoint endpoint, @Nullable JmsListenerContainerFactory factory) { - Assert.notNull(endpoint, "Endpoint must be set"); + Assert.notNull(endpoint, "Endpoint must not be null"); Assert.hasText(endpoint.getId(), "Endpoint id must be set"); // Factory may be null, we defer the resolution right before actually creating the container @@ -176,6 +182,7 @@ public class JmsListenerEndpointRegistrar implements BeanFactoryAware, Initializ synchronized (this.mutex) { if (this.startImmediately) { // register and start immediately + Assert.state(this.endpointRegistry != null, "No JmsListenerEndpointRegistry set"); this.endpointRegistry.registerListenerContainer(descriptor.endpoint, resolveContainerFactory(descriptor), true); } @@ -200,10 +207,12 @@ public class JmsListenerEndpointRegistrar implements BeanFactoryAware, Initializ public final JmsListenerEndpoint endpoint; + @Nullable public final JmsListenerContainerFactory containerFactory; public JmsListenerEndpointDescriptor(JmsListenerEndpoint endpoint, @Nullable JmsListenerContainerFactory containerFactory) { + this.endpoint = endpoint; this.containerFactory = containerFactory; } diff --git a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java index 2b3897ec7e..02ee4ba54e 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.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. @@ -68,6 +68,7 @@ public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecyc private int phase = Integer.MAX_VALUE; + @Nullable private ApplicationContext applicationContext; private boolean contextRefreshed; @@ -133,9 +134,9 @@ public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecyc Assert.notNull(endpoint, "Endpoint must not be null"); Assert.notNull(factory, "Factory must not be null"); - String id = endpoint.getId(); - Assert.notNull(id, "Endpoint id must not be null"); + Assert.hasText(id, "Endpoint id must be set"); + synchronized (this.listenerContainers) { if (this.listenerContainers.containsKey(id)) { throw new IllegalStateException("Another endpoint is already registered with id '" + id + "'"); diff --git a/spring-jms/src/main/java/org/springframework/jms/config/MethodJmsListenerEndpoint.java b/spring-jms/src/main/java/org/springframework/jms/config/MethodJmsListenerEndpoint.java index 5953eb8f82..fae136f1da 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/MethodJmsListenerEndpoint.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/MethodJmsListenerEndpoint.java @@ -49,14 +49,19 @@ import org.springframework.util.StringValueResolver; */ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint implements BeanFactoryAware { + @Nullable private Object bean; + @Nullable private Method method; + @Nullable private Method mostSpecificMethod; + @Nullable private MessageHandlerMethodFactory messageHandlerMethodFactory; + @Nullable private StringValueResolver embeddedValueResolver; @@ -67,6 +72,7 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint imple this.bean = bean; } + @Nullable public Object getBean() { return this.bean; } @@ -78,6 +84,7 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint imple this.method = method; } + @Nullable public Method getMethod() { return this.method; } @@ -92,16 +99,18 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint imple this.mostSpecificMethod = mostSpecificMethod; } + @Nullable public Method getMostSpecificMethod() { if (this.mostSpecificMethod != null) { return this.mostSpecificMethod; } - else if (AopUtils.isAopProxy(this.bean)) { + Method method = getMethod(); + if (method != null && AopUtils.isAopProxy(this.bean)) { Class target = AopProxyUtils.ultimateTargetClass(this.bean); - return AopUtils.getMostSpecificMethod(getMethod(), target); + return AopUtils.getMostSpecificMethod(method, target); } else { - return getMethod(); + return method; } } @@ -117,7 +126,7 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint imple /** * Set a value resolver for embedded placeholders and expressions. */ - public void setEmbeddedValueResolver(StringValueResolver embeddedValueResolver) { + public void setEmbeddedValueResolver(@Nullable StringValueResolver embeddedValueResolver) { this.embeddedValueResolver = embeddedValueResolver; } @@ -178,6 +187,9 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint imple @Nullable protected String getDefaultResponseDestination() { Method specificMethod = getMostSpecificMethod(); + if (specificMethod == null) { + return null; + } SendTo ann = getSendTo(specificMethod); if (ann != null) { Object[] destinations = ann.value(); diff --git a/spring-jms/src/main/java/org/springframework/jms/config/SimpleJmsListenerEndpoint.java b/spring-jms/src/main/java/org/springframework/jms/config/SimpleJmsListenerEndpoint.java index 8e6b538416..572de75c44 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/SimpleJmsListenerEndpoint.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/SimpleJmsListenerEndpoint.java @@ -31,6 +31,7 @@ import org.springframework.util.Assert; */ public class SimpleJmsListenerEndpoint extends AbstractJmsListenerEndpoint { + @Nullable private MessageListener messageListener; diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/CachedMessageProducer.java b/spring-jms/src/main/java/org/springframework/jms/connection/CachedMessageProducer.java index 93d7f92fb8..1f866b56a5 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/CachedMessageProducer.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/CachedMessageProducer.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. @@ -26,6 +26,8 @@ import javax.jms.QueueSender; import javax.jms.Topic; import javax.jms.TopicPublisher; +import org.springframework.lang.Nullable; + /** * JMS MessageProducer decorator that adapts calls to a shared MessageProducer * instance underneath, managing QoS settings locally within the decorator. @@ -37,10 +39,13 @@ class CachedMessageProducer implements MessageProducer, QueueSender, TopicPublis private final MessageProducer target; + @Nullable private Boolean originalDisableMessageID; + @Nullable private Boolean originalDisableMessageTimestamp; + @Nullable private Long originalDeliveryDelay; private int deliveryMode; diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.java b/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.java index 4e72b15469..bd8f713001 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.java @@ -491,6 +491,7 @@ public class CachingConnectionFactory extends SingleConnectionFactory { private final Destination destination; + @Nullable private String destinationString; public DestinationCacheKey(Destination destination) { @@ -544,10 +545,13 @@ public class CachingConnectionFactory extends SingleConnectionFactory { */ private static class ConsumerCacheKey extends DestinationCacheKey { + @Nullable private final String selector; + @Nullable private final Boolean noLocal; + @Nullable private final String subscription; private final boolean durable; diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java b/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java index 96f8982274..f38945eb82 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java @@ -53,6 +53,7 @@ public class JmsResourceHolder extends ResourceHolderSupport { private static final Log logger = LogFactory.getLog(JmsResourceHolder.class); + @Nullable private ConnectionFactory connectionFactory; private boolean frozen = false; diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/JmsTransactionManager.java b/spring-jms/src/main/java/org/springframework/jms/connection/JmsTransactionManager.java index ecfe31adfe..5f66a6706d 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/JmsTransactionManager.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/JmsTransactionManager.java @@ -93,6 +93,7 @@ import org.springframework.util.Assert; public class JmsTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean { + @Nullable private ConnectionFactory connectionFactory; @@ -327,6 +328,7 @@ public class JmsTransactionManager extends AbstractPlatformTransactionManager */ private static class JmsTransactionObject implements SmartTransactionObject { + @Nullable private JmsResourceHolder resourceHolder; public void setResourceHolder(@Nullable JmsResourceHolder resourceHolder) { @@ -344,7 +346,7 @@ public class JmsTransactionManager extends AbstractPlatformTransactionManager @Override public boolean isRollbackOnly() { - return this.resourceHolder.isRollbackOnly(); + return (this.resourceHolder != null && this.resourceHolder.isRollbackOnly()); } @Override diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/SingleConnectionFactory.java b/spring-jms/src/main/java/org/springframework/jms/connection/SingleConnectionFactory.java index 3f46284d3a..3fea35c505 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/SingleConnectionFactory.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/SingleConnectionFactory.java @@ -82,21 +82,27 @@ public class SingleConnectionFactory implements ConnectionFactory, QueueConnecti protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private ConnectionFactory targetConnectionFactory; + @Nullable private String clientId; + @Nullable private ExceptionListener exceptionListener; private boolean reconnectOnException = false; /** The target Connection */ + @Nullable private Connection connection; /** A hint whether to create a queue or topic connection */ + @Nullable private Boolean pubSubMode; /** An internal aggregator allowing for per-connection ExceptionListeners */ + @Nullable private AggregatedExceptionListener aggregatedExceptionListener; /** Whether the shared Connection has been started */ @@ -525,6 +531,7 @@ public class SingleConnectionFactory implements ConnectionFactory, QueueConnecti */ private class SharedConnectionInvocationHandler implements InvocationHandler { + @Nullable private ExceptionListener localExceptionListener; private boolean locallyStarted = false; diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/UserCredentialsConnectionFactoryAdapter.java b/spring-jms/src/main/java/org/springframework/jms/connection/UserCredentialsConnectionFactoryAdapter.java index 3916e8b141..a7bef236cd 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/UserCredentialsConnectionFactoryAdapter.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/UserCredentialsConnectionFactoryAdapter.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. @@ -27,6 +27,7 @@ import javax.jms.TopicConnectionFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.NamedThreadLocal; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -71,10 +72,13 @@ import org.springframework.util.StringUtils; public class UserCredentialsConnectionFactoryAdapter implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, InitializingBean { + @Nullable private ConnectionFactory targetConnectionFactory; + @Nullable private String username; + @Nullable private String password; private final ThreadLocal threadBoundCredentials = @@ -173,7 +177,7 @@ public class UserCredentialsConnectionFactoryAdapter * @see javax.jms.ConnectionFactory#createConnection(String, String) * @see javax.jms.ConnectionFactory#createConnection() */ - protected Connection doCreateConnection(String username, String password) throws JMSException { + protected Connection doCreateConnection(@Nullable String username, @Nullable String password) throws JMSException { ConnectionFactory target = obtainTargetConnectionFactory(); if (StringUtils.hasLength(username)) { return target.createConnection(username, password); @@ -219,7 +223,9 @@ public class UserCredentialsConnectionFactoryAdapter * @see javax.jms.QueueConnectionFactory#createQueueConnection(String, String) * @see javax.jms.QueueConnectionFactory#createQueueConnection() */ - protected QueueConnection doCreateQueueConnection(String username, String password) throws JMSException { + protected QueueConnection doCreateQueueConnection( + @Nullable String username, @Nullable String password) throws JMSException { + ConnectionFactory target = obtainTargetConnectionFactory(); if (!(target instanceof QueueConnectionFactory)) { throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a QueueConnectionFactory"); @@ -269,7 +275,9 @@ public class UserCredentialsConnectionFactoryAdapter * @see javax.jms.TopicConnectionFactory#createTopicConnection(String, String) * @see javax.jms.TopicConnectionFactory#createTopicConnection() */ - protected TopicConnection doCreateTopicConnection(String username, String password) throws JMSException { + protected TopicConnection doCreateTopicConnection( + @Nullable String username, @Nullable String password) throws JMSException { + ConnectionFactory target = obtainTargetConnectionFactory(); if (!(target instanceof TopicConnectionFactory)) { throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a TopicConnectionFactory"); diff --git a/spring-jms/src/main/java/org/springframework/jms/core/JmsMessagingTemplate.java b/spring-jms/src/main/java/org/springframework/jms/core/JmsMessagingTemplate.java index d5aa1d0bd6..abfcd1c04a 100644 --- a/spring-jms/src/main/java/org/springframework/jms/core/JmsMessagingTemplate.java +++ b/spring-jms/src/main/java/org/springframework/jms/core/JmsMessagingTemplate.java @@ -47,10 +47,12 @@ import org.springframework.util.Assert; public class JmsMessagingTemplate extends AbstractMessagingTemplate implements JmsMessageOperations, InitializingBean { + @Nullable private JmsTemplate jmsTemplate; private MessageConverter jmsMessageConverter = new MessagingMessageConverter(); + @Nullable private String defaultDestinationName; @@ -111,6 +113,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate /** * Return the configured {@link JmsTemplate}. */ + @Nullable public JmsTemplate getJmsTemplate() { return this.jmsTemplate; } @@ -158,7 +161,12 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate @Override public void afterPropertiesSet() { - Assert.notNull(getJmsTemplate(), "Property 'connectionFactory' or 'jmsTemplate' is required"); + Assert.notNull(this.jmsTemplate, "Property 'connectionFactory' or 'jmsTemplate' is required"); + } + + private JmsTemplate obtainJmsTemplate() { + Assert.state(this.jmsTemplate != null, "No JmsTemplate set"); + return this.jmsTemplate; } @@ -325,7 +333,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate @Override protected void doSend(Destination destination, Message message) { try { - this.jmsTemplate.send(destination, createMessageCreator(message)); + obtainJmsTemplate().send(destination, createMessageCreator(message)); } catch (JmsException ex) { throw convertJmsException(ex); @@ -334,7 +342,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate protected void doSend(String destinationName, Message message) { try { - this.jmsTemplate.send(destinationName, createMessageCreator(message)); + obtainJmsTemplate().send(destinationName, createMessageCreator(message)); } catch (JmsException ex) { throw convertJmsException(ex); @@ -344,7 +352,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate @Override protected Message doReceive(Destination destination) { try { - javax.jms.Message jmsMessage = this.jmsTemplate.receive(destination); + javax.jms.Message jmsMessage = obtainJmsTemplate().receive(destination); return convertJmsMessage(jmsMessage); } catch (JmsException ex) { @@ -355,7 +363,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate @Nullable protected Message doReceive(String destinationName) { try { - javax.jms.Message jmsMessage = this.jmsTemplate.receive(destinationName); + javax.jms.Message jmsMessage = obtainJmsTemplate().receive(destinationName); return convertJmsMessage(jmsMessage); } catch (JmsException ex) { @@ -366,7 +374,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate @Override protected Message doSendAndReceive(Destination destination, Message requestMessage) { try { - javax.jms.Message jmsMessage = this.jmsTemplate.sendAndReceive( + javax.jms.Message jmsMessage = obtainJmsTemplate().sendAndReceive( destination, createMessageCreator(requestMessage)); return convertJmsMessage(jmsMessage); } @@ -378,7 +386,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate @Nullable protected Message doSendAndReceive(String destinationName, Message requestMessage) { try { - javax.jms.Message jmsMessage = this.jmsTemplate.sendAndReceive( + javax.jms.Message jmsMessage = obtainJmsTemplate().sendAndReceive( destinationName, createMessageCreator(requestMessage)); return convertJmsMessage(jmsMessage); } diff --git a/spring-jms/src/main/java/org/springframework/jms/core/support/JmsGatewaySupport.java b/spring-jms/src/main/java/org/springframework/jms/core/support/JmsGatewaySupport.java index 9a54c30a11..8774fe1cca 100644 --- a/spring-jms/src/main/java/org/springframework/jms/core/support/JmsGatewaySupport.java +++ b/spring-jms/src/main/java/org/springframework/jms/core/support/JmsGatewaySupport.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. @@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.jms.core.JmsTemplate; +import org.springframework.lang.Nullable; /** * Convenient super class for application classes that need JMS access. @@ -45,6 +46,7 @@ public abstract class JmsGatewaySupport implements InitializingBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private JmsTemplate jmsTemplate; @@ -89,6 +91,7 @@ public abstract class JmsGatewaySupport implements InitializingBean { /** * Return the JmsTemplate for the gateway. */ + @Nullable public final JmsTemplate getJmsTemplate() { return this.jmsTemplate; } diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java index 14eae39fbc..bce077a319 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.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. @@ -61,14 +61,17 @@ import org.springframework.util.ClassUtils; public abstract class AbstractJmsListeningContainer extends JmsDestinationAccessor implements BeanNameAware, DisposableBean, SmartLifecycle { + @Nullable private String clientId; private boolean autoStartup = true; private int phase = Integer.MAX_VALUE; + @Nullable private String beanName; + @Nullable private Connection sharedConnection; private boolean sharedConnectionStarted = false; diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java index 24ba69e5fe..d16cd2cb87 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java @@ -143,28 +143,37 @@ import org.springframework.util.ErrorHandler; public abstract class AbstractMessageListenerContainer extends AbstractJmsListeningContainer implements MessageListenerContainer { + @Nullable private volatile Object destination; + @Nullable private volatile String messageSelector; + @Nullable private volatile Object messageListener; private boolean subscriptionDurable = false; private boolean subscriptionShared = false; + @Nullable private String subscriptionName; + @Nullable private Boolean replyPubSubDomain; + @Nullable private QosSettings replyQosSettings; private boolean pubSubNoLocal = false; + @Nullable private MessageConverter messageConverter; + @Nullable private ExceptionListener exceptionListener; + @Nullable private ErrorHandler errorHandler; private boolean exposeListenerSession = true; @@ -238,7 +247,8 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen * (never {@code null}). */ protected String getDestinationDescription() { - return this.destination.toString(); + Object destination = this.destination; + return (destination != null ? destination.toString() : ""); } /** diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.java index e2b9a292bd..e118b7f504 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.java @@ -87,6 +87,7 @@ public abstract class AbstractPollingMessageListenerContainer extends AbstractMe private boolean sessionTransactedCalled = false; + @Nullable private PlatformTransactionManager transactionManager; private DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); @@ -232,7 +233,8 @@ public abstract class AbstractPollingMessageListenerContainer extends AbstractMe * @throws JMSException if thrown by JMS methods * @see #doReceiveAndExecute */ - protected boolean receiveAndExecute(Object invoker, Session session, MessageConsumer consumer) + protected boolean receiveAndExecute( + Object invoker, @Nullable Session session, @Nullable MessageConsumer consumer) throws JMSException { if (this.transactionManager != null) { @@ -242,18 +244,10 @@ public abstract class AbstractPollingMessageListenerContainer extends AbstractMe try { messageReceived = doReceiveAndExecute(invoker, session, consumer, status); } - catch (JMSException ex) { - rollbackOnException(status, ex); + catch (JMSException | RuntimeException | Error ex) { + rollbackOnException(this.transactionManager, status, ex); throw ex; } - catch (RuntimeException ex) { - rollbackOnException(status, ex); - throw ex; - } - catch (Error err) { - rollbackOnException(status, err); - throw err; - } this.transactionManager.commit(status); return messageReceived; } @@ -398,10 +392,10 @@ public abstract class AbstractPollingMessageListenerContainer extends AbstractMe * @param status object representing the transaction * @param ex the thrown listener exception or error */ - private void rollbackOnException(TransactionStatus status, Throwable ex) { + private void rollbackOnException(PlatformTransactionManager manager, TransactionStatus status, Throwable ex) { logger.debug("Initiating transaction rollback on listener exception", ex); try { - this.transactionManager.rollback(status); + manager.rollback(status); } catch (RuntimeException ex2) { logger.error("Listener exception overridden by rollback exception", ex); diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java index b3313ea79c..77a03a8f3d 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java @@ -31,6 +31,7 @@ import org.springframework.jms.JmsException; import org.springframework.jms.support.JmsUtils; import org.springframework.jms.support.destination.CachingDestinationResolver; import org.springframework.jms.support.destination.DestinationResolver; +import org.springframework.lang.Nullable; import org.springframework.scheduling.SchedulingAwareRunnable; import org.springframework.scheduling.SchedulingTaskExecutor; import org.springframework.util.Assert; @@ -173,6 +174,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe private static final Constants constants = new Constants(DefaultMessageListenerContainer.class); + @Nullable private Executor taskExecutor; private BackOff backOff = new FixedBackOff(DEFAULT_RECOVERY_INTERVAL, Long.MAX_VALUE); @@ -199,6 +201,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe private volatile boolean interrupted = false; + @Nullable private Runnable stopCallback; private Object currentRecoveryMarker = new Object(); @@ -717,6 +720,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe */ @Override protected void doRescheduleTask(Object task) { + Assert.state(this.taskExecutor != null, "No TaskExecutor available"); this.taskExecutor.execute((Runnable) task); } @@ -1031,10 +1035,13 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe */ private class AsyncMessageListenerInvoker implements SchedulingAwareRunnable { + @Nullable private Session session; + @Nullable private MessageConsumer consumer; + @Nullable private Object lastRecoveryMarker; private boolean lastMessageSucceeded; diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java index 5850fc0fe1..bf1dc8df9d 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java @@ -29,6 +29,7 @@ import javax.jms.MessageConsumer; import javax.jms.Session; import org.springframework.jms.support.JmsUtils; +import org.springframework.lang.Nullable; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; @@ -67,10 +68,13 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta private int concurrentConsumers = 1; + @Nullable private Executor taskExecutor; + @Nullable private Set sessions; + @Nullable private Set consumers; private final Object consumersMonitor = new Object(); @@ -335,9 +339,11 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta for (MessageConsumer consumer : this.consumers) { JmsUtils.closeMessageConsumer(consumer); } - logger.debug("Closing JMS Sessions"); - for (Session session : this.sessions) { - JmsUtils.closeSession(session); + if (this.sessions != null) { + logger.debug("Closing JMS Sessions"); + for (Session session : this.sessions) { + JmsUtils.closeSession(session); + } } } } diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/adapter/AbstractAdaptableMessageListener.java b/spring-jms/src/main/java/org/springframework/jms/listener/adapter/AbstractAdaptableMessageListener.java index e65a667a6d..2e47a0119b 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/adapter/AbstractAdaptableMessageListener.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/adapter/AbstractAdaptableMessageListener.java @@ -60,6 +60,7 @@ public abstract class AbstractAdaptableMessageListener /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private Object defaultResponseDestination; private DestinationResolver destinationResolver = new DynamicDestinationResolver(); @@ -68,6 +69,7 @@ public abstract class AbstractAdaptableMessageListener private final MessagingMessageConverterAdapter messagingMessageConverter = new MessagingMessageConverterAdapter(); + @Nullable private QosSettings responseQosSettings; @@ -504,8 +506,10 @@ public abstract class AbstractAdaptableMessageListener private final javax.jms.Message message; + @Nullable private Object payload; + @Nullable private MessageHeaders headers; public LazyResolutionMessage(javax.jms.Message message) { diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java b/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java index 03ae0fa58b..febc13e1d2 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java @@ -44,22 +44,28 @@ public class JmsActivationSpecConfig { private static final Constants sessionConstants = new Constants(Session.class); + @Nullable private String destinationName; private boolean pubSubDomain = false; + @Nullable private Boolean replyPubSubDomain; + @Nullable private QosSettings replyQosSettings; private boolean subscriptionDurable = false; private boolean subscriptionShared = false; + @Nullable private String subscriptionName; + @Nullable private String clientId; + @Nullable private String messageSelector; private int acknowledgeMode = Session.AUTO_ACKNOWLEDGE; @@ -68,6 +74,7 @@ public class JmsActivationSpecConfig { private int prefetchSize = -1; + @Nullable private MessageConverter messageConverter; @@ -75,6 +82,7 @@ public class JmsActivationSpecConfig { this.destinationName = destinationName; } + @Nullable public String getDestinationName() { return this.destinationName; } @@ -104,6 +112,7 @@ public class JmsActivationSpecConfig { this.replyQosSettings = replyQosSettings; } + @Nullable public QosSettings getReplyQosSettings() { return this.replyQosSettings; } diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java b/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java index 20218beef9..4434a10b8b 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java @@ -60,6 +60,7 @@ public class JmsMessageEndpointManager extends GenericMessageEndpointManager private JmsActivationSpecFactory activationSpecFactory = new DefaultJmsActivationSpecFactory(); + @Nullable private JmsActivationSpecConfig activationSpecConfig; diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/StandardJmsActivationSpecFactory.java b/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/StandardJmsActivationSpecFactory.java index 675249c44c..aace9e6ecb 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/StandardJmsActivationSpecFactory.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/endpoint/StandardJmsActivationSpecFactory.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. @@ -51,10 +51,13 @@ import org.springframework.lang.Nullable; */ public class StandardJmsActivationSpecFactory implements JmsActivationSpecFactory { + @Nullable private Class activationSpecClass; + @Nullable private Map defaultProperties; + @Nullable private DestinationResolver destinationResolver; @@ -87,7 +90,7 @@ public class StandardJmsActivationSpecFactory implements JmsActivationSpecFactor * or {@link org.springframework.jms.support.destination.BeanFactoryDestinationResolver} * but not {@link org.springframework.jms.support.destination.DynamicDestinationResolver}. */ - public void setDestinationResolver(@Nullable DestinationResolver destinationResolver) { + public void setDestinationResolver(DestinationResolver destinationResolver) { this.destinationResolver = destinationResolver; } @@ -142,26 +145,28 @@ public class StandardJmsActivationSpecFactory implements JmsActivationSpecFactor */ protected void populateActivationSpecProperties(BeanWrapper bw, JmsActivationSpecConfig config) { String destinationName = config.getDestinationName(); - boolean pubSubDomain = config.isPubSubDomain(); - Object destination = destinationName; - if (this.destinationResolver != null) { - try { - destination = this.destinationResolver.resolveDestinationName(null, destinationName, pubSubDomain); - } - catch (JMSException ex) { - throw new DestinationResolutionException("Cannot resolve destination name [" + destinationName + "]", ex); + if (destinationName != null) { + boolean pubSubDomain = config.isPubSubDomain(); + Object destination = destinationName; + if (this.destinationResolver != null) { + try { + destination = this.destinationResolver.resolveDestinationName(null, destinationName, pubSubDomain); + } + catch (JMSException ex) { + throw new DestinationResolutionException( + "Cannot resolve destination name [" + destinationName + "]", ex); + } } + bw.setPropertyValue("destination", destination); + bw.setPropertyValue("destinationType", pubSubDomain ? Topic.class.getName() : Queue.class.getName()); } - bw.setPropertyValue("destination", destination); - bw.setPropertyValue("destinationType", pubSubDomain ? Topic.class.getName() : Queue.class.getName()); if (bw.isWritableProperty("subscriptionDurability")) { bw.setPropertyValue("subscriptionDurability", config.isSubscriptionDurable() ? "Durable" : "NonDurable"); } else if (config.isSubscriptionDurable()) { // Standard JCA 1.5 "subscriptionDurability" apparently not supported... - throw new IllegalArgumentException( - "Durable subscriptions not supported by underlying provider: " + this.activationSpecClass.getName()); + throw new IllegalArgumentException("Durable subscriptions not supported by underlying provider"); } if (config.isSubscriptionShared()) { throw new IllegalArgumentException("Shared subscriptions not supported for JCA-driven endpoints"); @@ -208,8 +213,7 @@ public class StandardJmsActivationSpecFactory implements JmsActivationSpecFactor } else if (ackMode == Session.DUPS_OK_ACKNOWLEDGE) { // Standard JCA 1.5 "acknowledgeMode" apparently not supported (e.g. WebSphere MQ 6.0.2.1) - throw new IllegalArgumentException( - "Dups-ok-acknowledge not supported by underlying provider: " + this.activationSpecClass.getName()); + throw new IllegalArgumentException("Dups-ok-acknowledge not supported by underlying provider"); } } diff --git a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java b/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java index cb8f4f2409..4b0c08602a 100644 --- a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java +++ b/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerClientInterceptor.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. @@ -74,8 +74,10 @@ import org.springframework.util.Assert; */ public class JmsInvokerClientInterceptor implements MethodInterceptor, InitializingBean { + @Nullable private ConnectionFactory connectionFactory; + @Nullable private Object queue; private DestinationResolver destinationResolver = new DynamicDestinationResolver(); diff --git a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java b/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java index b3177fa4dc..6b0f7630f6 100644 --- a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java +++ b/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java @@ -19,6 +19,7 @@ package org.springframework.jms.remoting; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -44,10 +45,13 @@ import org.springframework.util.ClassUtils; public class JmsInvokerProxyFactoryBean extends JmsInvokerClientInterceptor implements FactoryBean, BeanClassLoaderAware { + @Nullable private Class serviceInterface; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private Object serviceProxy; diff --git a/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java b/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java index 5f74a792a7..455dcc19b4 100644 --- a/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java +++ b/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java @@ -76,14 +76,17 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B private String encoding = DEFAULT_ENCODING; + @Nullable private String encodingPropertyName; + @Nullable private String typeIdPropertyName; private Map> idClassMappings = new HashMap<>(); private Map, String> classIdMappings = new HashMap<>(); + @Nullable private ClassLoader beanClassLoader; diff --git a/spring-jms/src/main/java/org/springframework/jms/support/destination/BeanFactoryDestinationResolver.java b/spring-jms/src/main/java/org/springframework/jms/support/destination/BeanFactoryDestinationResolver.java index 477e5506b3..8c654e8069 100644 --- a/spring-jms/src/main/java/org/springframework/jms/support/destination/BeanFactoryDestinationResolver.java +++ b/spring-jms/src/main/java/org/springframework/jms/support/destination/BeanFactoryDestinationResolver.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. @@ -38,6 +38,7 @@ import org.springframework.util.Assert; */ public class BeanFactoryDestinationResolver implements DestinationResolver, BeanFactoryAware { + @Nullable private BeanFactory beanFactory; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/MessageHeaders.java b/spring-messaging/src/main/java/org/springframework/messaging/MessageHeaders.java index 38e2bae9af..8f3a16dacb 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/MessageHeaders.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/MessageHeaders.java @@ -96,7 +96,8 @@ public class MessageHeaders implements Map, Serializable { private static final IdGenerator defaultIdGenerator = new AlternativeJdkIdGenerator(); - private static volatile IdGenerator idGenerator = null; + @Nullable + private static volatile IdGenerator idGenerator; private final Map headers; @@ -162,7 +163,8 @@ public class MessageHeaders implements Map, Serializable { } protected static IdGenerator getIdGenerator() { - return (idGenerator != null ? idGenerator : defaultIdGenerator); + IdGenerator generator = idGenerator; + return (generator != null ? generator : defaultIdGenerator); } @Nullable diff --git a/spring-messaging/src/main/java/org/springframework/messaging/MessagingException.java b/spring-messaging/src/main/java/org/springframework/messaging/MessagingException.java index ceacbbee76..c67bd2419e 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/MessagingException.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/MessagingException.java @@ -29,6 +29,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class MessagingException extends NestedRuntimeException { + @Nullable private final Message failedMessage; @@ -63,6 +64,7 @@ public class MessagingException extends NestedRuntimeException { } + @Nullable public Message getFailedMessage() { return this.failedMessage; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java index cafe394898..7be2268242 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java @@ -49,6 +49,7 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter private final List supportedMimeTypes; + @Nullable private ContentTypeResolver contentTypeResolver = new DefaultContentTypeResolver(); private boolean strictContentTypeMatch = false; @@ -91,13 +92,14 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter * ignore all messages. *

By default, a {@code DefaultContentTypeResolver} instance is used. */ - public void setContentTypeResolver(ContentTypeResolver resolver) { + public void setContentTypeResolver(@Nullable ContentTypeResolver resolver) { this.contentTypeResolver = resolver; } /** * Return the configured {@link ContentTypeResolver}. */ + @Nullable public ContentTypeResolver getContentTypeResolver() { return this.contentTypeResolver; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java index ba0848f97d..7f93963692 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java @@ -64,6 +64,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { private ObjectMapper objectMapper; + @Nullable private Boolean prettyPrint; @@ -73,7 +74,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { */ public MappingJackson2MessageConverter() { super(new MimeType("application", "json", StandardCharsets.UTF_8)); - initObjectMapper(); + this.objectMapper = initObjectMapper(); } /** @@ -84,14 +85,15 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { */ public MappingJackson2MessageConverter(MimeType... supportedMimeTypes) { super(Arrays.asList(supportedMimeTypes)); - initObjectMapper(); + this.objectMapper = initObjectMapper(); } - private void initObjectMapper() { - this.objectMapper = new ObjectMapper(); - this.objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false); - this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private ObjectMapper initObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return objectMapper; } /** diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java index 21bc1d240e..469c71012d 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java @@ -49,8 +49,10 @@ import org.springframework.util.MimeType; */ public class MarshallingMessageConverter extends AbstractMessageConverter { + @Nullable private Marshaller marshaller; + @Nullable private Unmarshaller unmarshaller; @@ -97,6 +99,7 @@ public class MarshallingMessageConverter extends AbstractMessageConverter { /** * Return the configured Marshaller. */ + @Nullable public Marshaller getMarshaller() { return this.marshaller; } @@ -111,6 +114,7 @@ public class MarshallingMessageConverter extends AbstractMessageConverter { /** * Return the configured unmarshaller. */ + @Nullable public Unmarshaller getUnmarshaller() { return this.unmarshaller; } @@ -123,7 +127,7 @@ public class MarshallingMessageConverter extends AbstractMessageConverter { } @Override - protected boolean canConvertTo(Object payload, MessageHeaders headers) { + protected boolean canConvertTo(Object payload, @Nullable MessageHeaders headers) { return (supportsMimeType(headers) && this.marshaller != null && this.marshaller.supports(payload.getClass())); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractDestinationResolvingMessagingTemplate.java b/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractDestinationResolvingMessagingTemplate.java index afc59d2091..eb948832a7 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractDestinationResolvingMessagingTemplate.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractDestinationResolvingMessagingTemplate.java @@ -40,7 +40,8 @@ public abstract class AbstractDestinationResolvingMessagingTemplate extends A DestinationResolvingMessageReceivingOperations, DestinationResolvingMessageRequestReplyOperations { - private volatile DestinationResolver destinationResolver; + @Nullable + private DestinationResolver destinationResolver; /** @@ -58,6 +59,7 @@ public abstract class AbstractDestinationResolvingMessagingTemplate extends A /** * Return the configured destination resolver. */ + @Nullable public DestinationResolver getDestinationResolver() { return this.destinationResolver; } @@ -70,6 +72,7 @@ public abstract class AbstractDestinationResolvingMessagingTemplate extends A } protected final D resolveDestination(String destinationName) { + Assert.state(this.destinationResolver != null, "DestinationResolver is required to resolve destination names"); return this.destinationResolver.resolveDestination(destinationName); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java b/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java index c119190ad7..8eae29a4f3 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageSendingTemplate.java @@ -52,9 +52,10 @@ public abstract class AbstractMessageSendingTemplate implements MessageSendin protected final Log logger = LogFactory.getLog(getClass()); - private volatile D defaultDestination; + @Nullable + private D defaultDestination; - private volatile MessageConverter converter = new SimpleMessageConverter(); + private MessageConverter converter = new SimpleMessageConverter(); /** diff --git a/spring-messaging/src/main/java/org/springframework/messaging/core/BeanFactoryMessageChannelDestinationResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/core/BeanFactoryMessageChannelDestinationResolver.java index d185c3c7b9..8a45054747 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/core/BeanFactoryMessageChannelDestinationResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/core/BeanFactoryMessageChannelDestinationResolver.java @@ -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. @@ -19,6 +19,7 @@ package org.springframework.messaging.core; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.lang.Nullable; import org.springframework.messaging.MessageChannel; import org.springframework.util.Assert; @@ -33,6 +34,7 @@ import org.springframework.util.Assert; public class BeanFactoryMessageChannelDestinationResolver implements DestinationResolver, BeanFactoryAware { + @Nullable private BeanFactory beanFactory; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/core/CachingDestinationResolverProxy.java b/spring-messaging/src/main/java/org/springframework/messaging/core/CachingDestinationResolverProxy.java index d163041499..ba542f9234 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/core/CachingDestinationResolverProxy.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/core/CachingDestinationResolverProxy.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,6 +20,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -37,6 +38,7 @@ public class CachingDestinationResolverProxy implements DestinationResolver resolvedDestinationCache = new ConcurrentHashMap<>(); + @Nullable private DestinationResolver targetDestinationResolver; @@ -85,6 +87,7 @@ public class CachingDestinationResolverProxy implements DestinationResolver beanType; @@ -65,6 +66,7 @@ public class HandlerMethod { private final MethodParameter[] parameters; + @Nullable private HandlerMethod resolvedFromHandlerMethod; @@ -109,7 +111,10 @@ public class HandlerMethod { this.bean = beanName; this.beanFactory = beanFactory; Class beanType = beanFactory.getType(beanName); - this.beanType = (beanType != null ? ClassUtils.getUserClass(beanType) : null); + if (beanType == null) { + throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'"); + } + this.beanType = ClassUtils.getUserClass(beanType); this.method = method; this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); this.parameters = initMethodParameters(); @@ -204,7 +209,7 @@ public class HandlerMethod { /** * Return the actual return value type. */ - public MethodParameter getReturnValueType(Object returnValue) { + public MethodParameter getReturnValueType(@Nullable Object returnValue) { return new ReturnValueMethodParameter(returnValue); } @@ -244,6 +249,7 @@ public class HandlerMethod { * resolved via {@link #createWithResolvedBean()}. * @since 4.3 */ + @Nullable public HandlerMethod getResolvedFromHandlerMethod() { return this.resolvedFromHandlerMethod; } @@ -255,6 +261,7 @@ public class HandlerMethod { public HandlerMethod createWithResolvedBean() { Object handler = this.bean; if (this.bean instanceof String) { + Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory"); String beanName = (String) this.bean; handler = this.beanFactory.getBean(beanName); } @@ -333,9 +340,10 @@ public class HandlerMethod { */ private class ReturnValueMethodParameter extends HandlerMethodParameter { + @Nullable private final Object returnValue; - public ReturnValueMethodParameter(Object returnValue) { + public ReturnValueMethodParameter(@Nullable Object returnValue) { super(-1); this.returnValue = returnValue; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.java index 576093ee38..60f9d1c0e3 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.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. @@ -21,12 +21,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import org.springframework.core.ExceptionDepthComparator; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; +import org.springframework.util.ConcurrentReferenceHashMap; /** * Cache exception handling method mappings and provide options to look up a method @@ -39,11 +38,9 @@ import org.springframework.util.ClassUtils; */ public abstract class AbstractExceptionHandlerMethodResolver { - private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis"); + private final Map, Method> mappedMethods = new ConcurrentReferenceHashMap<>(16); - private final Map, Method> mappedMethods = new ConcurrentHashMap<>(16); - - private final Map, Method> exceptionLookupCache = new ConcurrentHashMap<>(16); + private final Map, Method> exceptionLookupCache = new ConcurrentReferenceHashMap<>(16); /** @@ -109,9 +106,9 @@ public abstract class AbstractExceptionHandlerMethodResolver { Method method = this.exceptionLookupCache.get(exceptionType); if (method == null) { method = getMappedMethod(exceptionType); - this.exceptionLookupCache.put(exceptionType, method != null ? method : NO_METHOD_FOUND); + this.exceptionLookupCache.put(exceptionType, method); } - return method != NO_METHOD_FOUND ? method : null; + return method; } /** 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 604296b97b..23910f3e2f 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 @@ -259,6 +259,7 @@ public class InvocableHandlerMethod extends HandlerMethod { private class AsyncResultMethodParameter extends HandlerMethodParameter { + @Nullable private final Object returnValue; private final ResolvableType returnType; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java index bbbdfd4ee8..80675ea9e3 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java @@ -69,11 +69,12 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH private PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("{", "}", null, false); + @Nullable private MessageHeaderInitializer headerInitializer; public SendToMethodReturnValueHandler(SimpMessageSendingOperations messagingTemplate, boolean annotationRequired) { - Assert.notNull(messagingTemplate, "messagingTemplate must not be null"); + Assert.notNull(messagingTemplate, "'messagingTemplate' must not be null"); this.messagingTemplate = messagingTemplate; this.annotationRequired = annotationRequired; } @@ -276,6 +277,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH private static class DestinationVariablePlaceholderResolver implements PlaceholderResolver { + @Nullable private final Map vars; public DestinationVariablePlaceholderResolver(@Nullable Map vars) { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java index 13fc91457e..381637bbb4 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java @@ -101,10 +101,13 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan private boolean slashPathSeparator = true; + @Nullable private Validator validator; + @Nullable private StringValueResolver valueResolver; + @Nullable private MessageHeaderInitializer headerInitializer; private final Object lifecycleMonitor = new Object(); @@ -221,6 +224,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan /** * Return the configured Validator instance. */ + @Nullable public Validator getValidator() { return this.validator; } @@ -252,6 +256,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan /** * Return the configured header initializer. */ + @Nullable public MessageHeaderInitializer getHeaderInitializer() { return this.headerInitializer; } @@ -331,7 +336,9 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan // Annotation-based return value types SendToMethodReturnValueHandler sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, true); - sendToHandler.setHeaderInitializer(this.headerInitializer); + if (this.headerInitializer != null) { + sendToHandler.setHeaderInitializer(this.headerInitializer); + } handlers.add(sendToHandler); SubscriptionMethodReturnValueHandler subscriptionHandler = diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java index 00ff3a91ba..eb200ba64b 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java @@ -59,6 +59,7 @@ public abstract class AbstractBrokerMessageHandler private final Collection destinationPrefixes; + @Nullable private ApplicationEventPublisher eventPublisher; private AtomicBoolean brokerAvailable = new AtomicBoolean(false); @@ -132,6 +133,7 @@ public abstract class AbstractBrokerMessageHandler this.eventPublisher = publisher; } + @Nullable public ApplicationEventPublisher getApplicationEventPublisher() { return this.eventPublisher; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistry.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistry.java index 0c32a4381e..fc75d12ba5 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistry.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistry.java @@ -492,6 +492,7 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry { private final String id; + @Nullable private final Expression selectorExpression; public Subscription(String id, @Nullable Expression selector) { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/SimpleBrokerMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/SimpleBrokerMessageHandler.java index 62430cbff9..eda220ea64 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/SimpleBrokerMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/SimpleBrokerMessageHandler.java @@ -56,16 +56,22 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler { private SubscriptionRegistry subscriptionRegistry; + @Nullable private PathMatcher pathMatcher; + @Nullable private Integer cacheLimit; + @Nullable private TaskScheduler taskScheduler; + @Nullable private long[] heartbeatValue; + @Nullable private ScheduledFuture heartbeatFuture; + @Nullable private MessageHeaderInitializer headerInitializer; @@ -112,7 +118,7 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler { * @see DefaultSubscriptionRegistry#setPathMatcher * @see org.springframework.util.AntPathMatcher */ - public void setPathMatcher(PathMatcher pathMatcher) { + public void setPathMatcher(@Nullable PathMatcher pathMatcher) { this.pathMatcher = pathMatcher; initPathMatcherToUse(); } @@ -133,7 +139,7 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler { * @see DefaultSubscriptionRegistry#setCacheLimit * @see DefaultSubscriptionRegistry#DEFAULT_CACHE_LIMIT */ - public void setCacheLimit(Integer cacheLimit) { + public void setCacheLimit(@Nullable Integer cacheLimit) { this.cacheLimit = cacheLimit; initCacheLimitToUse(); } @@ -216,7 +222,7 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler { @Override public void startInternal() { publishBrokerAvailableEvent(); - if (getTaskScheduler() != null) { + if (this.taskScheduler != null) { long interval = initHeartbeatTaskDelay(); if (interval > 0) { this.heartbeatFuture = this.taskScheduler.scheduleWithFixedDelay(new HeartbeatTask(), interval); @@ -384,6 +390,7 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler { private final String sessiondId; + @Nullable private final Principal user; private final long readInterval; @@ -416,6 +423,7 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler { return this.sessiondId; } + @Nullable public Principal getUser() { return this.user; } @@ -458,7 +466,10 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler { if (info.getWriteInterval() > 0 && (now - info.getLastWriteTime()) > info.getWriteInterval()) { SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create(SimpMessageType.HEARTBEAT); accessor.setSessionId(info.getSessiondId()); - accessor.setUser(info.getUser()); + Principal user = info.getUser(); + if (user != null) { + accessor.setUser(user); + } initHeaders(accessor); MessageHeaders headers = accessor.getMessageHeaders(); getClientOutboundChannel().send(MessageBuilder.createMessage(EMPTY_PAYLOAD, headers)); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java index 85b028439e..538cca5c54 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/AbstractMessageBrokerConfiguration.java @@ -91,12 +91,16 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC "com.fasterxml.jackson.databind.ObjectMapper", AbstractMessageBrokerConfiguration.class.getClassLoader()); + @Nullable private ApplicationContext applicationContext; + @Nullable private ChannelRegistration clientInboundChannelRegistration; + @Nullable private ChannelRegistration clientOutboundChannelRegistration; + @Nullable private MessageBrokerRegistry brokerRegistry; @@ -112,6 +116,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC this.applicationContext = applicationContext; } + @Nullable public ApplicationContext getApplicationContext() { return this.applicationContext; } @@ -418,7 +423,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC protected Validator simpValidator() { Validator validator = getValidator(); if (validator == null) { - if (this.applicationContext.containsBean(MVC_VALIDATOR_NAME)) { + if (this.applicationContext != null && this.applicationContext.containsBean(MVC_VALIDATOR_NAME)) { validator = this.applicationContext.getBean(MVC_VALIDATOR_NAME, Validator.class); } else if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/ChannelRegistration.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/ChannelRegistration.java index 2692f6c2b2..e59d299759 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/ChannelRegistration.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/ChannelRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors.7 + * Copyright 2002-2017 the original author or authors.7 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.springframework.lang.Nullable; import org.springframework.messaging.support.ChannelInterceptor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -32,6 +33,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; */ public class ChannelRegistration { + @Nullable private TaskExecutorRegistration registration; private final List interceptors = new ArrayList<>(); @@ -71,6 +73,7 @@ public class ChannelRegistration { return (this.registration != null); } + @Nullable protected TaskExecutorRegistration getTaskExecRegistration() { return this.registration; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/MessageBrokerRegistry.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/MessageBrokerRegistry.java index 5ac7e975c7..25a5cbabd1 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/MessageBrokerRegistry.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/MessageBrokerRegistry.java @@ -40,18 +40,24 @@ public class MessageBrokerRegistry { private final MessageChannel clientOutboundChannel; + @Nullable private SimpleBrokerRegistration simpleBrokerRegistration; + @Nullable private StompBrokerRelayRegistration brokerRelayRegistration; private final ChannelRegistration brokerChannelRegistration = new ChannelRegistration(); + @Nullable private String[] applicationDestinationPrefixes; + @Nullable private String userDestinationPrefix; + @Nullable private PathMatcher pathMatcher; + @Nullable private Integer cacheLimit; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/SimpleBrokerRegistration.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/SimpleBrokerRegistration.java index ab240affc0..bd2d8471ba 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/SimpleBrokerRegistration.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/SimpleBrokerRegistration.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. @@ -16,6 +16,7 @@ package org.springframework.messaging.simp.config; +import org.springframework.lang.Nullable; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.SubscribableChannel; import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler; @@ -29,8 +30,10 @@ import org.springframework.scheduling.TaskScheduler; */ public class SimpleBrokerRegistration extends AbstractBrokerRegistration { + @Nullable private TaskScheduler taskScheduler; + @Nullable private long[] heartbeat; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/StompBrokerRelayRegistration.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/StompBrokerRelayRegistration.java index b6fbfef02e..835467729e 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/StompBrokerRelayRegistration.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/StompBrokerRelayRegistration.java @@ -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. @@ -16,6 +16,7 @@ package org.springframework.messaging.simp.config; +import org.springframework.lang.Nullable; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.SubscribableChannel; import org.springframework.messaging.simp.stomp.StompBrokerRelayMessageHandler; @@ -41,16 +42,21 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration { private String systemPasscode = "guest"; + @Nullable private Long systemHeartbeatSendInterval; + @Nullable private Long systemHeartbeatReceiveInterval; + @Nullable private String virtualHost; private boolean autoStartup = true; + @Nullable private String userDestinationBroadcast; + @Nullable private String userRegistryBroadcast; @@ -184,6 +190,7 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration { return this; } + @Nullable protected String getUserDestinationBroadcast() { return this.userDestinationBroadcast; } @@ -202,6 +209,7 @@ public class StompBrokerRelayRegistration extends AbstractBrokerRegistration { return this; } + @Nullable protected String getUserRegistryBroadcast() { return this.userRegistryBroadcast; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/TaskExecutorRegistration.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/TaskExecutorRegistration.java index 39ce080272..45abd15974 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/config/TaskExecutorRegistration.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/config/TaskExecutorRegistration.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. @@ -16,6 +16,7 @@ package org.springframework.messaging.simp.config; +import org.springframework.lang.Nullable; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; /** @@ -26,6 +27,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; */ public class TaskExecutorRegistration { + @Nullable private ThreadPoolTaskExecutor taskExecutor; private int corePoolSize = Runtime.getRuntime().availableProcessors() * 2; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.java index 6212cef1ee..49492511f7 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.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.List; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; +import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; @@ -53,6 +54,7 @@ public class BufferingStompDecoder { private final Queue chunks = new LinkedBlockingQueue<>(); + @Nullable private volatile Integer expectedContentLength; @@ -102,7 +104,8 @@ public class BufferingStompDecoder { this.chunks.add(newBuffer); checkBufferLimits(); - if (this.expectedContentLength != null && getBufferSize() < this.expectedContentLength) { + Integer contentLength = this.expectedContentLength; + if (contentLength != null && getBufferSize() < contentLength) { return Collections.emptyList(); } @@ -136,8 +139,9 @@ public class BufferingStompDecoder { } private void checkBufferLimits() { - if (this.expectedContentLength != null) { - if (this.expectedContentLength > this.bufferSizeLimit) { + Integer contentLength = this.expectedContentLength; + if (contentLength != null) { + if (contentLength > this.bufferSizeLimit) { throw new StompConversionException( "STOMP 'content-length' header value " + this.expectedContentLength + " exceeds configured buffer size limit " + this.bufferSizeLimit); @@ -163,6 +167,7 @@ public class BufferingStompDecoder { /** * Get the expected content length of the currently buffered, incomplete STOMP frame. */ + @Nullable public Integer getExpectedContentLength() { return this.expectedContentLength; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java index 97f07bcf39..78de2e3572 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java @@ -84,6 +84,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { private MessageConverter converter = new SimpleMessageConverter(); + @Nullable private TaskScheduler taskScheduler; private long receiptTimeLimit = 15 * 1000; @@ -91,8 +92,10 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { private volatile boolean autoReceiptEnabled; + @Nullable private volatile TcpConnection connection; + @Nullable private volatile String version; private final AtomicInteger subscriptionIndex = new AtomicInteger(); @@ -167,6 +170,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { /** * Return the configured TaskScheduler to use for receipt tracking. */ + @Nullable public TaskScheduler getTaskScheduler() { return this.taskScheduler; } @@ -464,13 +468,15 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { if (connect == null || connected == null) { return; } + TcpConnection con = this.connection; + Assert.state(con != null, "No TcpConnection available"); if (connect[0] > 0 && connected[1] > 0) { long interval = Math.max(connect[0], connected[1]); - this.connection.onWriteInactivity(new WriteInactivityTask(), interval); + con.onWriteInactivity(new WriteInactivityTask(), interval); } if (connect[1] > 0 && connected[0] > 0) { - final long interval = Math.max(connect[1], connected[0]) * HEARTBEAT_MULTIPLIER; - this.connection.onReadInactivity(new ReadInactivityTask(), interval); + long interval = Math.max(connect[1], connected[0]) * HEARTBEAT_MULTIPLIER; + con.onReadInactivity(new ReadInactivityTask(), interval); } } @@ -514,14 +520,17 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { private class ReceiptHandler implements Receiptable { + @Nullable private final String receiptId; private final List receiptCallbacks = new ArrayList<>(2); private final List receiptLostCallbacks = new ArrayList<>(2); + @Nullable private ScheduledFuture future; + @Nullable private Boolean result; public ReceiptHandler(@Nullable String receiptId) { @@ -666,7 +675,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession { if (conn != null) { conn.send(HEARTBEAT).addCallback( new ListenableFutureCallback() { - public void onSuccess(Void result) { + public void onSuccess(@Nullable Void result) { } public void onFailure(Throwable ex) { handleFailure(ex); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java index d9bd5c7a66..cf84259550 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java @@ -123,10 +123,13 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler private final Map systemSubscriptions = new HashMap<>(4); + @Nullable private String virtualHost; + @Nullable private TcpOperations tcpClient; + @Nullable private MessageHeaderInitializer headerInitializer; private final Stats stats = new Stats(); @@ -389,7 +392,9 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler protected void startInternal() { if (this.tcpClient == null) { StompDecoder decoder = new StompDecoder(); - decoder.setHeaderInitializer(getHeaderInitializer()); + if (this.headerInitializer != null) { + decoder.setHeaderInitializer(this.headerInitializer); + } ReactorNettyCodec codec = new StompReactorNettyCodec(decoder); this.tcpClient = new ReactorNettyTcpClient<>(this.relayHost, this.relayPort, codec); } @@ -422,11 +427,13 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler @Override protected void stopInternal() { publishBrokerUnavailableEvent(); - try { - this.tcpClient.shutdown().get(5000, TimeUnit.MILLISECONDS); - } - catch (Throwable ex) { - logger.error("Error in shutdown of TCP client", ex); + if (this.tcpClient != null) { + try { + this.tcpClient.shutdown().get(5000, TimeUnit.MILLISECONDS); + } + catch (Throwable ex) { + logger.error("Error in shutdown of TCP client", ex); + } } } @@ -514,6 +521,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler StompConnectionHandler handler = new StompConnectionHandler(sessionId, stompAccessor); this.connectionHandlers.put(sessionId, handler); this.stats.incrementConnectCount(); + Assert.state(this.tcpClient != null, "No TCP client available"); this.tcpClient.connect(handler); } else if (StompCommand.DISCONNECT.equals(command)) { @@ -553,6 +561,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler private final StompHeaderAccessor connectHeaders; + @Nullable private volatile TcpConnection tcpConnection; private volatile boolean isStompConnected; @@ -585,7 +594,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler logger.debug("TCP connection opened in session=" + getSessionId()); } this.tcpConnection = connection; - this.tcpConnection.onReadInactivity(() -> { + connection.onReadInactivity(() -> { if (this.tcpConnection != null && !this.isStompConnected) { handleTcpConnectionFailure("No CONNECTED frame received in " + MAX_TIME_TO_CONNECTED_FRAME + " ms.", null); @@ -691,6 +700,9 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler return; } + TcpConnection con = this.tcpConnection; + Assert.state(con != null, "No TcpConnection available"); + long clientSendInterval = this.connectHeaders.getHeartbeat()[0]; long clientReceiveInterval = this.connectHeaders.getHeartbeat()[1]; long serverSendInterval = connectedHeaders.getHeartbeat()[0]; @@ -698,25 +710,16 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler if (clientSendInterval > 0 && serverReceiveInterval > 0) { long interval = Math.max(clientSendInterval, serverReceiveInterval); - this.tcpConnection.onWriteInactivity(() -> { - TcpConnection conn = this.tcpConnection; - if (conn != null) { - conn.send(HEARTBEAT_MESSAGE).addCallback( - new ListenableFutureCallback() { - public void onSuccess(Void result) { - } - - public void onFailure(Throwable ex) { - handleTcpConnectionFailure("Failed to forward heartbeat: " + ex.getMessage(), ex); - } - }); - } - }, interval); + con.onWriteInactivity(() -> + con.send(HEARTBEAT_MESSAGE).addCallback( + result -> {}, + ex -> handleTcpConnectionFailure( + "Failed to forward heartbeat: " + ex.getMessage(), ex)), interval); } if (clientReceiveInterval > 0 && serverSendInterval > 0) { final long interval = Math.max(clientReceiveInterval, serverSendInterval) * HEARTBEAT_MULTIPLIER; - this.tcpConnection.onReadInactivity(() - -> handleTcpConnectionFailure("No messages received in " + interval + " ms.", null), interval); + con.onReadInactivity( + () -> handleTcpConnectionFailure("No messages received in " + interval + " ms.", null), interval); } } @@ -809,7 +812,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler ListenableFuture future = conn.send((Message) messageToSend); future.addCallback(new ListenableFutureCallback() { @Override - public void onSuccess(Void result) { + public void onSuccess(@Nullable Void result) { if (accessor.getCommand() == StompCommand.DISCONNECT) { afterDisconnectSent(accessor); } @@ -910,13 +913,10 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler if (conn != null) { MessageHeaders headers = accessor.getMessageHeaders(); conn.send(MessageBuilder.createMessage(EMPTY_PAYLOAD, headers)).addCallback( - new ListenableFutureCallback() { - public void onSuccess(Void result) { - } - public void onFailure(Throwable ex) { - String error = "Failed to subscribe in \"system\" session."; - handleTcpConnectionFailure(error, ex); - } + result -> {}, + ex -> { + String error = "Failed to subscribe in \"system\" session."; + handleTcpConnectionFailure(error, ex); }); } } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompClientSupport.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompClientSupport.java index 2f41c2e40d..db00db65aa 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompClientSupport.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompClientSupport.java @@ -71,7 +71,7 @@ public abstract class StompClientSupport { /** * Configure a scheduler to use for heartbeats and for receipt tracking. - *

Note: some transports have built-in support to work + *

Note: Some transports have built-in support to work * with heartbeats and therefore do not require a TaskScheduler. * Receipts however, if needed, do require a TaskScheduler to be configured. *

By default, this is not set. diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java index 8f526ae557..961b3ca27e 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java @@ -53,6 +53,7 @@ public class StompDecoder { private static final Log logger = LogFactory.getLog(StompDecoder.class); + @Nullable private MessageHeaderInitializer headerInitializer; @@ -60,7 +61,7 @@ public class StompDecoder { * Configure a {@link MessageHeaderInitializer} to apply to the headers of * {@link Message}s from decoded STOMP frames. */ - public void setHeaderInitializer(@Nullable MessageHeaderInitializer headerInitializer) { + public void setHeaderInitializer(MessageHeaderInitializer headerInitializer) { this.headerInitializer = headerInitializer; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java index f91cc6e5c4..ed141b9447 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/DefaultUserDestinationResolver.java @@ -207,7 +207,7 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver { Set sessionIds; SimpUser user = this.userRegistry.getUser(userName); if (user != null) { - if (user.getSession(sessionId) != null) { + if (sessionId != null && user.getSession(sessionId) != null) { sessionIds = Collections.singleton(sessionId); } else { @@ -264,6 +264,7 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver { private final Set sessionIds; + @Nullable private final String user; public ParseResult(String sourceDest, String actualDest, String subscribeDest, diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/MultiServerUserRegistry.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/MultiServerUserRegistry.java index cde55e78ec..c21640379e 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/MultiServerUserRegistry.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/MultiServerUserRegistry.java @@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.core.Ordered; +import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.converter.MessageConverter; import org.springframework.util.Assert; @@ -97,7 +98,7 @@ public class MultiServerUserRegistry implements SimpUserRegistry, SmartApplicati } @Override - public boolean supportsSourceType(Class sourceType) { + public boolean supportsSourceType(@Nullable Class sourceType) { return (this.delegateApplicationEvents && ((SmartApplicationListener) this.localRegistry).supportsSourceType(sourceType)); } @@ -278,6 +279,7 @@ public class MultiServerUserRegistry implements SimpUserRegistry, SmartApplicati private Set sessions; /* Cross-server session lookup (e.g. user connected to multiple servers) */ + @Nullable private SessionLookup sessionLookup; /** diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpSubscription.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpSubscription.java index 39c363c98d..9cb9e0ee9b 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpSubscription.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpSubscription.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. @@ -25,17 +25,17 @@ package org.springframework.messaging.simp.user; public interface SimpSubscription { /** - * Return the id associated of the subscription, never {@code null}. + * Return the id associated of the subscription (never {@code null}). */ String getId(); /** - * Return the session of the subscription, never {@code null}. + * Return the session of the subscription (never {@code null}). */ SimpSession getSession(); /** - * Return the subscription's destination, never {@code null}. + * Return the subscription's destination (never {@code null}). */ String getDestination(); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpUser.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpUser.java index 177d88c2cb..3d0a2808db 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpUser.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/SimpUser.java @@ -44,7 +44,7 @@ public interface SimpUser { * @return the matching session, or {@code null} if none found */ @Nullable - SimpSession getSession(@Nullable String sessionId); + SimpSession getSession(String sessionId); /** * Return the sessions for the user. diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java index 2546056d71..0352af4646 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java @@ -61,8 +61,10 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec private final MessageSendingOperations messagingTemplate; + @Nullable private BroadcastHandler broadcastHandler; + @Nullable private MessageHeaderInitializer headerInitializer; private final Object lifecycleMonitor = new Object(); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationResult.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationResult.java index a2101940ea..0e1680d152 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationResult.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationResult.java @@ -37,6 +37,7 @@ public class UserDestinationResult { private final String subscribeDestination; + @Nullable private final String user; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserRegistryMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserRegistryMessageHandler.java index 983127cd84..d23470d801 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserRegistryMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserRegistryMessageHandler.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.messaging.simp.user; import java.util.concurrent.ScheduledFuture; import org.springframework.context.ApplicationListener; +import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessagingException; @@ -35,8 +36,7 @@ import org.springframework.util.Assert; * application servers and periodically broadcasts the content of the local * user registry. * - * The aggregated information - * is maintained in a {@link MultiServerUserRegistry}. + *

The aggregated information is maintained in a {@link MultiServerUserRegistry}. * * @author Rossen Stoyanchev * @since 4.2 @@ -53,6 +53,7 @@ public class UserRegistryMessageHandler implements MessageHandler, ApplicationLi private final UserRegistryTask schedulerTask = new UserRegistryTask(); + @Nullable private volatile ScheduledFuture scheduledFuture; private long registryExpirationPeriod = 20 * 1000; @@ -62,8 +63,8 @@ public class UserRegistryMessageHandler implements MessageHandler, ApplicationLi * Constructor. * @param userRegistry the registry with local and remote user registry information * @param brokerTemplate template for broadcasting local registry information - * @param broadcastDestination the destination to broadcast to - * @param scheduler + * @param broadcastDestination the destination to broadcast to + * @param scheduler the task scheduler to use */ public UserRegistryMessageHandler(MultiServerUserRegistry userRegistry, SimpMessagingTemplate brokerTemplate, String broadcastDestination, TaskScheduler scheduler) { @@ -112,9 +113,12 @@ public class UserRegistryMessageHandler implements MessageHandler, ApplicationLi long delay = getRegistryExpirationPeriod() / 2; this.scheduledFuture = this.scheduler.scheduleWithFixedDelay(this.schedulerTask, delay); } - else if (this.scheduledFuture != null ){ - this.scheduledFuture.cancel(true); - this.scheduledFuture = null; + else { + ScheduledFuture future = this.scheduledFuture; + if (future != null ){ + future.cancel(true); + this.scheduledFuture = null; + } } } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java b/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java index 402ee02966..35a0626c14 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/support/ErrorMessage.java @@ -18,6 +18,7 @@ package org.springframework.messaging.support; import java.util.Map; +import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; @@ -44,6 +45,7 @@ public class ErrorMessage extends GenericMessage { private static final long serialVersionUID = -5470210965279837728L; + @Nullable private final Message originalMessage; @@ -126,6 +128,7 @@ public class ErrorMessage extends GenericMessage { * where the ErrorMessage was created. * @since 5.0 */ + @Nullable public Message getOriginalMessage() { return this.originalMessage; } @@ -135,10 +138,7 @@ public class ErrorMessage extends GenericMessage { if (this.originalMessage == null) { return super.toString(); } - - StringBuilder sb = new StringBuilder(super.toString()); - sb.append(" for original ").append(this.originalMessage); - return sb.toString(); + return super.toString() + " for original " + this.originalMessage; } } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java b/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java index a00b02a214..5b6a657a12 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java @@ -36,6 +36,7 @@ import org.springframework.messaging.SubscribableChannel; */ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel { + @Nullable private final Executor executor; private final List executorInterceptors = new ArrayList<>(4); @@ -60,6 +61,7 @@ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel { } + @Nullable public Executor getExecutor() { return this.executor; } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/support/MessageBuilder.java b/spring-messaging/src/main/java/org/springframework/messaging/support/MessageBuilder.java index b3ece48bbd..ff9413e08c 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/support/MessageBuilder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/support/MessageBuilder.java @@ -39,6 +39,7 @@ public final class MessageBuilder { private final T payload; + @Nullable private final Message originalMessage; private MessageHeaderAccessor headerAccessor; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/support/MessageHeaderAccessor.java b/spring-messaging/src/main/java/org/springframework/messaging/support/MessageHeaderAccessor.java index 0a764f1a48..e58bcc5e72 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/support/MessageHeaderAccessor.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/support/MessageHeaderAccessor.java @@ -130,6 +130,7 @@ public class MessageHeaderAccessor { private boolean enableTimestamp = false; + @Nullable private IdGenerator idGenerator; diff --git a/spring-orm/src/main/java/org/springframework/orm/ObjectOptimisticLockingFailureException.java b/spring-orm/src/main/java/org/springframework/orm/ObjectOptimisticLockingFailureException.java index 0f6c5c1225..65e3b6bbff 100644 --- a/spring-orm/src/main/java/org/springframework/orm/ObjectOptimisticLockingFailureException.java +++ b/spring-orm/src/main/java/org/springframework/orm/ObjectOptimisticLockingFailureException.java @@ -29,8 +29,10 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ObjectOptimisticLockingFailureException extends OptimisticLockingFailureException { + @Nullable private Object persistentClass; + @Nullable private Object identifier; @@ -151,6 +153,7 @@ public class ObjectOptimisticLockingFailureException extends OptimisticLockingFa /** * Return the identifier of the object for which the locking failed. */ + @Nullable public Object getIdentifier() { return this.identifier; } diff --git a/spring-orm/src/main/java/org/springframework/orm/ObjectRetrievalFailureException.java b/spring-orm/src/main/java/org/springframework/orm/ObjectRetrievalFailureException.java index 69ee15d0a5..77885879d3 100644 --- a/spring-orm/src/main/java/org/springframework/orm/ObjectRetrievalFailureException.java +++ b/spring-orm/src/main/java/org/springframework/orm/ObjectRetrievalFailureException.java @@ -29,8 +29,10 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ObjectRetrievalFailureException extends DataRetrievalFailureException { + @Nullable private Object persistentClass; + @Nullable private Object identifier; @@ -125,6 +127,7 @@ public class ObjectRetrievalFailureException extends DataRetrievalFailureExcepti /** * Return the identifier of the object that was not found. */ + @Nullable public Object getIdentifier() { return this.identifier; } diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/ConfigurableJtaPlatform.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/ConfigurableJtaPlatform.java index bda31c9d64..fb82e05add 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/ConfigurableJtaPlatform.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/ConfigurableJtaPlatform.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. @@ -45,6 +45,7 @@ class ConfigurableJtaPlatform implements JtaPlatform { private final UserTransaction userTransaction; + @Nullable private final TransactionSynchronizationRegistry transactionSynchronizationRegistry; @@ -55,7 +56,9 @@ class ConfigurableJtaPlatform implements JtaPlatform { * @param ut the JTA UserTransaction reference (optional) * @param tsr the JTA 1.1 TransactionSynchronizationRegistry (optional) */ - public ConfigurableJtaPlatform(TransactionManager tm, @Nullable UserTransaction ut, @Nullable TransactionSynchronizationRegistry tsr) { + public ConfigurableJtaPlatform(TransactionManager tm, @Nullable UserTransaction ut, + @Nullable TransactionSynchronizationRegistry tsr) { + Assert.notNull(tm, "TransactionManager reference must not be null"); this.transactionManager = tm; this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm)); diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java index ce9356d4d1..bef9dd2c99 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java @@ -110,8 +110,10 @@ import org.springframework.util.Assert; public class HibernateTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, BeanFactoryAware, InitializingBean { + @Nullable private SessionFactory sessionFactory; + @Nullable private DataSource dataSource; private boolean autodetectDataSource = true; @@ -122,12 +124,14 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana private boolean hibernateManagedSession = false; + @Nullable private Object entityInterceptor; /** * Just needed for entityInterceptorBeanName. * @see #setEntityInterceptorBeanName */ + @Nullable private BeanFactory beanFactory; @@ -788,12 +792,14 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana */ private class HibernateTransactionObject extends JdbcTransactionObjectSupport { + @Nullable private SessionHolder sessionHolder; private boolean newSessionHolder; private boolean newSession; + @Nullable private Integer previousHoldability; public void setSession(Session session) { @@ -850,7 +856,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana } public void setRollbackOnly() { - this.sessionHolder.setRollbackOnly(); + getSessionHolder().setRollbackOnly(); if (hasConnectionHolder()) { getConnectionHolder().setRollbackOnly(); } @@ -858,14 +864,14 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana @Override public boolean isRollbackOnly() { - return this.sessionHolder.isRollbackOnly() || + return getSessionHolder().isRollbackOnly() || (hasConnectionHolder() && getConnectionHolder().isRollbackOnly()); } @Override public void flush() { try { - this.sessionHolder.getSession().flush(); + getSessionHolder().getSession().flush(); } catch (HibernateException ex) { throw convertHibernateAccessException(ex); @@ -888,6 +894,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana private final SessionHolder sessionHolder; + @Nullable private final ConnectionHolder connectionHolder; private SuspendedResourcesHolder(SessionHolder sessionHolder, @Nullable ConnectionHolder conHolder) { diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java index 02cbb73d76..a9b68a8301 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java @@ -63,52 +63,75 @@ import org.springframework.util.Assert; public class LocalSessionFactoryBean extends HibernateExceptionTranslator implements FactoryBean, ResourceLoaderAware, InitializingBean, DisposableBean { + @Nullable private DataSource dataSource; + @Nullable private Resource[] configLocations; + @Nullable private String[] mappingResources; + @Nullable private Resource[] mappingLocations; + @Nullable private Resource[] cacheableMappingLocations; + @Nullable private Resource[] mappingJarLocations; + @Nullable private Resource[] mappingDirectoryLocations; + @Nullable private Interceptor entityInterceptor; + @Nullable private ImplicitNamingStrategy implicitNamingStrategy; + @Nullable private PhysicalNamingStrategy physicalNamingStrategy; + @Nullable private Object jtaTransactionManager; + @Nullable private MultiTenantConnectionProvider multiTenantConnectionProvider; + @Nullable private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; + @Nullable private TypeFilter[] entityTypeFilters; + @Nullable private Properties hibernateProperties; + @Nullable private Class[] annotatedClasses; + @Nullable private String[] annotatedPackages; + @Nullable private String[] packagesToScan; + @Nullable private AsyncTaskExecutor bootstrapExecutor; private boolean metadataSourcesAccessed = false; + @Nullable private MetadataSources metadataSources; + @Nullable private ResourcePatternResolver resourcePatternResolver; + @Nullable private Configuration configuration; + @Nullable private SessionFactory sessionFactory; @@ -372,7 +395,7 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator * @param resourceLoader the ResourceLoader to use (never {@code null}) */ @Override - public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { + public void setResourceLoader(ResourceLoader resourceLoader) { this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); } @@ -409,7 +432,7 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator if (this.mappingResources != null) { // Register given Hibernate mapping definitions, contained in resource files. for (String mapping : this.mappingResources) { - Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader()); + Resource mr = new ClassPathResource(mapping.trim(), getResourceLoader().getClassLoader()); sfb.addInputStream(mr.getInputStream()); } } @@ -543,7 +566,9 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator @Override public void destroy() { - this.sessionFactory.close(); + if (this.sessionFactory != null) { + this.sessionFactory.close(); + } } } diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java index c18d1bccb3..5d41f59873 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java @@ -94,6 +94,7 @@ public class LocalSessionFactoryBuilder extends Configuration { private final ResourcePatternResolver resourcePatternResolver; + @Nullable private TypeFilter[] entityTypeFilters = DEFAULT_ENTITY_TYPE_FILTERS; diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionHolder.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionHolder.java index a81a467bde..39789d1e92 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionHolder.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SessionHolder.java @@ -40,8 +40,10 @@ public class SessionHolder extends ResourceHolderSupport { private final Session session; + @Nullable private Transaction transaction; + @Nullable private FlushMode previousFlushMode; diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringSessionContext.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringSessionContext.java index 250fd60921..df7dd0cb5f 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringSessionContext.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringSessionContext.java @@ -28,6 +28,7 @@ import org.hibernate.context.spi.CurrentSessionContext; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.springframework.lang.Nullable; import org.springframework.transaction.support.TransactionSynchronizationManager; /** @@ -47,8 +48,10 @@ public class SpringSessionContext implements CurrentSessionContext { private final SessionFactoryImplementor sessionFactory; + @Nullable private TransactionManager transactionManager; + @Nullable private CurrentSessionContext jtaSessionContext; @@ -102,7 +105,7 @@ public class SpringSessionContext implements CurrentSessionContext { return session; } - if (this.transactionManager != null) { + if (this.transactionManager != null && this.jtaSessionContext != null) { try { if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) { Session session = this.jtaSessionContext.currentSession(); diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java index 71756c621a..2e61bea004 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/support/HibernateDaoSupport.java @@ -55,6 +55,7 @@ import org.springframework.util.Assert; */ public abstract class HibernateDaoSupport extends DaoSupport { + @Nullable private HibernateTemplate hibernateTemplate; @@ -110,6 +111,7 @@ public abstract class HibernateDaoSupport extends DaoSupport { * {@code new HibernateTemplate(getSessionFactory())}, in which case * you're allowed to customize the settings on the resulting instance. */ + @Nullable public final HibernateTemplate getHibernateTemplate() { return this.hibernateTemplate; } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java index 69117cdd22..3cff33700b 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java @@ -55,6 +55,7 @@ import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -92,35 +93,47 @@ public abstract class AbstractEntityManagerFactoryBean implements /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private PersistenceProvider persistenceProvider; + @Nullable private String persistenceUnitName; private final Map jpaPropertyMap = new HashMap<>(); + @Nullable private Class entityManagerFactoryInterface; + @Nullable private Class entityManagerInterface; + @Nullable private JpaDialect jpaDialect; + @Nullable private JpaVendorAdapter jpaVendorAdapter; + @Nullable private AsyncTaskExecutor bootstrapExecutor; private ClassLoader beanClassLoader = getClass().getClassLoader(); + @Nullable private BeanFactory beanFactory; + @Nullable private String beanName; /** Raw EntityManagerFactory as returned by the PersistenceProvider */ + @Nullable private EntityManagerFactory nativeEntityManagerFactory; /** Future for lazily initializing raw target EntityManagerFactory */ + @Nullable private Future nativeEntityManagerFactoryFuture; /** Exposed client-level EntityManagerFactory proxy */ + @Nullable private EntityManagerFactory entityManagerFactory; @@ -489,6 +502,7 @@ public abstract class AbstractEntityManagerFactoryBean implements return this.nativeEntityManagerFactory; } else { + Assert.state(this.nativeEntityManagerFactoryFuture != null, "No native EntityManagerFactory available"); try { return this.nativeEntityManagerFactoryFuture.get(); } @@ -538,10 +552,12 @@ public abstract class AbstractEntityManagerFactoryBean implements */ @Override public void destroy() { - if (logger.isInfoEnabled()) { - logger.info("Closing JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'"); + if (this.entityManagerFactory != null) { + if (logger.isInfoEnabled()) { + logger.info("Closing JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'"); + } + this.entityManagerFactory.close(); } - this.entityManagerFactory.close(); } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java index 3c8e096feb..2cd6caf988 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java @@ -317,7 +317,7 @@ public abstract class EntityManagerFactoryUtils { * @param emf the EntityManagerFactory that the EntityManager has been created with * @see JpaDialect#cleanupTransaction */ - private static void cleanupTransaction(Object transactionData, EntityManagerFactory emf) { + private static void cleanupTransaction(@Nullable Object transactionData, EntityManagerFactory emf) { if (emf instanceof EntityManagerFactoryInfo) { EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf; JpaDialect jpaDialect = emfInfo.getJpaDialect(); @@ -443,8 +443,10 @@ public abstract class EntityManagerFactoryUtils { extends ResourceHolderSynchronization implements Ordered { + @Nullable private final Object transactionData; + @Nullable private final JpaDialect jpaDialect; private final boolean newEntityManager; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerHolder.java b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerHolder.java index 28fc980feb..c927fb2e74 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerHolder.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerHolder.java @@ -41,6 +41,7 @@ public class EntityManagerHolder extends ResourceHolderSupport { private boolean transactionActive; + @Nullable private SavepointManager savepointManager; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java index fb664c6a69..d3afe0fa7b 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java @@ -248,6 +248,7 @@ public abstract class ExtendedEntityManagerCreator { private final EntityManager target; + @Nullable private final PersistenceExceptionTranslator exceptionTranslator; private final boolean jta; @@ -423,12 +424,14 @@ public abstract class ExtendedEntityManagerCreator { private final EntityManager entityManager; + @Nullable private final PersistenceExceptionTranslator exceptionTranslator; public volatile boolean closeOnCompletion = false; public ExtendedEntityManagerSynchronization( - EntityManager em, PersistenceExceptionTranslator exceptionTranslator) { + EntityManager em, @Nullable PersistenceExceptionTranslator exceptionTranslator) { + super(new EntityManagerHolder(em), em); this.entityManager = em; this.exceptionTranslator = exceptionTranslator; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java index cdc0185460..ebb6f8110c 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java @@ -113,12 +113,15 @@ import org.springframework.util.CollectionUtils; public class JpaTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, BeanFactoryAware, InitializingBean { + @Nullable private EntityManagerFactory entityManagerFactory; + @Nullable private String persistenceUnitName; private final Map jpaPropertyMap = new HashMap<>(); + @Nullable private DataSource dataSource; private JpaDialect jpaDialect = new DefaultJpaDialect(); @@ -630,19 +633,23 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager */ private class JpaTransactionObject extends JdbcTransactionObjectSupport { + @Nullable private EntityManagerHolder entityManagerHolder; private boolean newEntityManagerHolder; + @Nullable private Object transactionData; public void setEntityManagerHolder( @Nullable EntityManagerHolder entityManagerHolder, boolean newEntityManagerHolder) { + this.entityManagerHolder = entityManagerHolder; this.newEntityManagerHolder = newEntityManagerHolder; } public EntityManagerHolder getEntityManagerHolder() { + Assert.state(this.entityManagerHolder != null, "No EntityManagerHolder available"); return this.entityManagerHolder; } @@ -660,18 +667,19 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager public void setTransactionData(@Nullable Object transactionData) { this.transactionData = transactionData; - this.entityManagerHolder.setTransactionActive(true); + getEntityManagerHolder().setTransactionActive(true); if (transactionData instanceof SavepointManager) { - this.entityManagerHolder.setSavepointManager((SavepointManager) transactionData); + getEntityManagerHolder().setSavepointManager((SavepointManager) transactionData); } } + @Nullable public Object getTransactionData() { return this.transactionData; } public void setRollbackOnly() { - EntityTransaction tx = this.entityManagerHolder.getEntityManager().getTransaction(); + EntityTransaction tx = getEntityManagerHolder().getEntityManager().getTransaction(); if (tx.isActive()) { tx.setRollbackOnly(); } @@ -682,14 +690,14 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager @Override public boolean isRollbackOnly() { - EntityTransaction tx = this.entityManagerHolder.getEntityManager().getTransaction(); + EntityTransaction tx = getEntityManagerHolder().getEntityManager().getTransaction(); return tx.getRollbackOnly(); } @Override public void flush() { try { - this.entityManagerHolder.getEntityManager().flush(); + getEntityManagerHolder().getEntityManager().flush(); } catch (RuntimeException ex) { throw DataAccessUtils.translateIfNecessary(ex, getJpaDialect()); @@ -698,7 +706,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager @Override public Object createSavepoint() throws TransactionException { - if (this.entityManagerHolder.isRollbackOnly()) { + if (getEntityManagerHolder().isRollbackOnly()) { throw new CannotCreateTransactionException( "Cannot create savepoint for transaction which is already marked as rollback-only"); } @@ -708,7 +716,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager @Override public void rollbackToSavepoint(Object savepoint) throws TransactionException { getSavepointManager().rollbackToSavepoint(savepoint); - this.entityManagerHolder.resetRollbackOnly(); + getEntityManagerHolder().resetRollbackOnly(); } @Override @@ -739,6 +747,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager private final EntityManagerHolder entityManagerHolder; + @Nullable private final ConnectionHolder connectionHolder; private SuspendedResourcesHolder(EntityManagerHolder emHolder, @Nullable ConnectionHolder conHolder) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java index 58ec815adc..23c3339dc3 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java @@ -30,6 +30,7 @@ import org.springframework.context.weaving.LoadTimeWeaverAware; import org.springframework.core.io.ResourceLoader; import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.jdbc.datasource.lookup.SingleDataSourceLookup; +import org.springframework.lang.Nullable; import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor; @@ -88,11 +89,13 @@ import org.springframework.util.ClassUtils; public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean implements ResourceLoaderAware, LoadTimeWeaverAware { + @Nullable private PersistenceUnitManager persistenceUnitManager; private final DefaultPersistenceUnitManager internalPersistenceUnitManager = new DefaultPersistenceUnitManager(); + @Nullable private PersistenceUnitInfo persistenceUnitInfo; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java index d9709ae866..884fce9d84 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java @@ -179,10 +179,12 @@ public abstract class SharedEntityManagerCreator { private final EntityManagerFactory targetFactory; + @Nullable private final Map properties; private final boolean synchronizedWithTransaction; + @Nullable private transient volatile ClassLoader proxyClassLoader; public SharedEntityManagerInvocationHandler( @@ -341,6 +343,7 @@ public abstract class SharedEntityManagerCreator { private final Query target; + @Nullable private EntityManager em; public DeferredQueryInvocationHandler(Query target, EntityManager em) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java index 00950dbfef..79bc416ca9 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java @@ -127,30 +127,41 @@ public class DefaultPersistenceUnitManager private String[] persistenceXmlLocations = new String[] {DEFAULT_PERSISTENCE_XML_LOCATION}; + @Nullable private String defaultPersistenceUnitRootLocation = ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION; + @Nullable private String defaultPersistenceUnitName = ORIGINAL_DEFAULT_PERSISTENCE_UNIT_NAME; + @Nullable private String[] packagesToScan; + @Nullable private String[] mappingResources; + @Nullable private SharedCacheMode sharedCacheMode; + @Nullable private ValidationMode validationMode; private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); + @Nullable private DataSource defaultDataSource; + @Nullable private DataSource defaultJtaDataSource; + @Nullable private PersistenceUnitPostProcessor[] persistenceUnitPostProcessors; + @Nullable private LoadTimeWeaver loadTimeWeaver; private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + @Nullable private CandidateComponentsIndex componentsIndex; private final Set persistenceUnitInfoNames = new HashSet<>(); @@ -447,10 +458,10 @@ public class DefaultPersistenceUnitManager if (pui.getPersistenceUnitRootUrl() == null) { pui.setPersistenceUnitRootUrl(determineDefaultPersistenceUnitRootUrl()); } - if (pui.getJtaDataSource() == null) { + if (pui.getJtaDataSource() == null && this.defaultJtaDataSource != null) { pui.setJtaDataSource(this.defaultJtaDataSource); } - if (pui.getNonJtaDataSource() == null) { + if (pui.getNonJtaDataSource() == null && this.defaultDataSource != null) { pui.setNonJtaDataSource(this.defaultDataSource); } if (this.sharedCacheMode != null) { @@ -517,17 +528,14 @@ public class DefaultPersistenceUnitManager */ private SpringPersistenceUnitInfo buildDefaultPersistenceUnitInfo() { SpringPersistenceUnitInfo scannedUnit = new SpringPersistenceUnitInfo(); - scannedUnit.setPersistenceUnitName(this.defaultPersistenceUnitName); + if (this.defaultPersistenceUnitName != null) { + scannedUnit.setPersistenceUnitName(this.defaultPersistenceUnitName); + } scannedUnit.setExcludeUnlistedClasses(true); if (this.packagesToScan != null) { for (String pkg : this.packagesToScan) { - if (this.componentsIndex != null) { - addPackageFromIndex(scannedUnit, pkg); - } - else { - scanPackage(scannedUnit, pkg); - } + scanPackage(scannedUnit, pkg); } } @@ -555,18 +563,18 @@ public class DefaultPersistenceUnitManager return scannedUnit; } - private void addPackageFromIndex(SpringPersistenceUnitInfo scannedUnit, String pkg) { - Set candidates = new HashSet<>(); - for (AnnotationTypeFilter filter : entityTypeFilters) { - candidates.addAll(this.componentsIndex - .getCandidateTypes(pkg, filter.getAnnotationType().getName())); - } - candidates.forEach(scannedUnit::addManagedClassName); - Set managedPackages = this.componentsIndex.getCandidateTypes(pkg, "package-info"); - managedPackages.forEach(scannedUnit::addManagedPackage); - } - private void scanPackage(SpringPersistenceUnitInfo scannedUnit, String pkg) { + if (this.componentsIndex != null) { + Set candidates = new HashSet<>(); + for (AnnotationTypeFilter filter : entityTypeFilters) { + candidates.addAll(this.componentsIndex.getCandidateTypes(pkg, filter.getAnnotationType().getName())); + } + candidates.forEach(scannedUnit::addManagedClassName); + Set managedPackages = this.componentsIndex.getCandidateTypes(pkg, "package-info"); + managedPackages.forEach(scannedUnit::addManagedPackage); + return; + } + try { String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(pkg) + CLASS_RESOURCE_PATTERN; @@ -709,7 +717,7 @@ public class DefaultPersistenceUnitManager throw new IllegalStateException("All persistence units from " + ObjectUtils.nullSafeToString(this.persistenceXmlLocations) + " already obtained"); } - if (this.persistenceUnitInfos.size() > 1) { + if (this.persistenceUnitInfos.size() > 1 && this.defaultPersistenceUnitName != null) { return obtainPersistenceUnitInfo(this.defaultPersistenceUnitName); } PersistenceUnitInfo pui = this.persistenceUnitInfos.values().iterator().next(); diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java index 6691f5d275..ce9aff630b 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java @@ -27,6 +27,7 @@ import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.DataSource; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** @@ -44,20 +45,26 @@ import org.springframework.util.ClassUtils; */ public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { + @Nullable private String persistenceUnitName; + @Nullable private String persistenceProviderClassName; + @Nullable private PersistenceUnitTransactionType transactionType; + @Nullable private DataSource nonJtaDataSource; + @Nullable private DataSource jtaDataSource; private final List mappingFileNames = new LinkedList<>(); private List jarFileUrls = new LinkedList<>(); + @Nullable private URL persistenceUnitRootUrl; private final List managedClassNames = new LinkedList<>(); @@ -74,6 +81,7 @@ public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { private String persistenceXMLSchemaVersion = "2.0"; + @Nullable private String persistenceProviderPackageName; @@ -82,6 +90,7 @@ public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { } @Override + @Nullable public String getPersistenceUnitName() { return this.persistenceUnitName; } @@ -91,6 +100,7 @@ public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { } @Override + @Nullable public String getPersistenceProviderClassName() { return this.persistenceProviderClassName; } @@ -218,13 +228,11 @@ public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { } public void addProperty(String name, String value) { - if (this.properties == null) { - this.properties = new Properties(); - } this.properties.setProperty(name, value); } public void setProperties(Properties properties) { + Assert.notNull(properties, "Properties must not be null"); this.properties = properties; } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java index 77b4c87608..a694d11397 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java @@ -38,8 +38,10 @@ import org.springframework.util.Assert; */ class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { + @Nullable private LoadTimeWeaver loadTimeWeaver; + @Nullable private ClassLoader classLoader; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java b/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java index 30d5b8199f..137626ba6c 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.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. @@ -74,10 +74,13 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter { public static final String DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME = "entityManagerFactory"; + @Nullable private String entityManagerFactoryBeanName; + @Nullable private String persistenceUnitName; + @Nullable private volatile EntityManagerFactory entityManagerFactory; @@ -97,6 +100,7 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter { * Return the bean name of the EntityManagerFactory to fetch from Spring's * root application context. */ + @Nullable protected String getEntityManagerFactoryBeanName() { return this.entityManagerFactoryBeanName; } @@ -202,10 +206,12 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter { * @see #lookupEntityManagerFactory() */ protected EntityManagerFactory lookupEntityManagerFactory(HttpServletRequest request) { - if (this.entityManagerFactory == null) { - this.entityManagerFactory = lookupEntityManagerFactory(); + EntityManagerFactory emf = this.entityManagerFactory; + if (emf == null) { + emf = lookupEntityManagerFactory(); + this.entityManagerFactory = emf; } - return this.entityManagerFactory; + return emf; } /** diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java index b56ef814b2..40b7fbceae 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java @@ -61,6 +61,7 @@ import org.springframework.orm.jpa.EntityManagerFactoryUtils; import org.springframework.orm.jpa.EntityManagerProxy; import org.springframework.orm.jpa.ExtendedEntityManagerCreator; import org.springframework.orm.jpa.SharedEntityManagerCreator; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -169,27 +170,30 @@ public class PersistenceAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, Serializable { + @Nullable private Object jndiEnvironment; private boolean resourceRef = true; + @Nullable private transient Map persistenceUnits; + @Nullable private transient Map persistenceContexts; + @Nullable private transient Map extendedPersistenceContexts; private transient String defaultPersistenceUnitName = ""; private int order = Ordered.LOWEST_PRECEDENCE - 4; + @Nullable private transient ListableBeanFactory beanFactory; - private transient final Map injectionMetadataCache = - new ConcurrentHashMap<>(256); + private transient final Map injectionMetadataCache = new ConcurrentHashMap<>(256); - private final Map extendedEntityManagersToClose = - new ConcurrentHashMap<>(16); + private final Map extendedEntityManagersToClose = new ConcurrentHashMap<>(16); /** @@ -516,9 +520,6 @@ public class PersistenceAnnotationBeanPostProcessor protected EntityManagerFactory findEntityManagerFactory(@Nullable String unitName, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { - if (this.beanFactory == null) { - throw new IllegalStateException("ListableBeanFactory required for EntityManagerFactory bean lookup"); - } String unitNameForLookup = (unitName != null ? unitName : ""); if ("".equals(unitNameForLookup)) { unitNameForLookup = this.defaultPersistenceUnitName; @@ -542,6 +543,8 @@ public class PersistenceAnnotationBeanPostProcessor protected EntityManagerFactory findNamedEntityManagerFactory(String unitName, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { + Assert.state(this.beanFactory != null, "ListableBeanFactory required for EntityManagerFactory bean lookup"); + EntityManagerFactory emf = EntityManagerFactoryUtils.findEntityManagerFactory(this.beanFactory, unitName); if (requestingBeanName != null && this.beanFactory instanceof ConfigurableBeanFactory) { ((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName); @@ -557,6 +560,8 @@ public class PersistenceAnnotationBeanPostProcessor protected EntityManagerFactory findDefaultEntityManagerFactory(@Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { + Assert.state(this.beanFactory != null, "ListableBeanFactory required for EntityManagerFactory bean lookup"); + if (this.beanFactory instanceof ConfigurableListableBeanFactory) { // Fancy variant with dependency registration ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) this.beanFactory; @@ -617,10 +622,12 @@ public class PersistenceAnnotationBeanPostProcessor private final String unitName; + @Nullable private PersistenceContextType type; private boolean synchronizedWithTransaction = false; + @Nullable private Properties properties; public PersistenceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/support/SharedEntityManagerBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/support/SharedEntityManagerBean.java index 4c5b44592d..df68fab2a5 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/support/SharedEntityManagerBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/support/SharedEntityManagerBean.java @@ -21,6 +21,7 @@ import javax.persistence.EntityManagerFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.orm.jpa.EntityManagerFactoryAccessor; import org.springframework.orm.jpa.EntityManagerFactoryInfo; import org.springframework.orm.jpa.SharedEntityManagerCreator; @@ -51,10 +52,12 @@ import org.springframework.util.Assert; public class SharedEntityManagerBean extends EntityManagerFactoryAccessor implements FactoryBean, InitializingBean { + @Nullable private Class entityManagerInterface; private boolean synchronizedWithTransaction = true; + @Nullable private EntityManager shared; diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java index f7010135ae..f81b417bc7 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.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. @@ -24,6 +24,7 @@ import javax.persistence.PersistenceException; import org.eclipse.persistence.sessions.UnitOfWork; import org.springframework.jdbc.datasource.ConnectionHandle; +import org.springframework.lang.Nullable; import org.springframework.orm.jpa.DefaultJpaDialect; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; @@ -114,6 +115,7 @@ public class EclipseLinkJpaDialect extends DefaultJpaDialect { private final EntityManager entityManager; + @Nullable private Connection connection; public EclipseLinkConnectionHandle(EntityManager entityManager) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java index 965c598315..c7befaccb8 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java @@ -322,10 +322,13 @@ public class HibernateJpaDialect extends DefaultJpaDialect { private final Session session; + @Nullable private final FlushMode previousFlushMode; + @Nullable private final Connection preparedCon; + @Nullable private final Integer previousIsolationLevel; public SessionTransactionData(Session session, @Nullable FlushMode previousFlushMode, @@ -358,6 +361,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect { private static class HibernateConnectionHandle implements ConnectionHandle { + @Nullable private static volatile Method connectionMethodToUse; private final Session session; @@ -377,11 +381,13 @@ public class HibernateJpaDialect extends DefaultJpaDialect { public static Connection doGetConnection(Session session) { try { - if (connectionMethodToUse == null) { + Method methodToUse = connectionMethodToUse; + if (methodToUse == null) { // Reflective lookup to find SessionImpl's connection() method on Hibernate 4.x/5.x - connectionMethodToUse = session.getClass().getMethod("connection"); + methodToUse = session.getClass().getMethod("connection"); + connectionMethodToUse = methodToUse; } - Connection con = (Connection) ReflectionUtils.invokeMethod(connectionMethodToUse, session); + Connection con = (Connection) ReflectionUtils.invokeMethod(methodToUse, session); Assert.state(con != null, "No Connection from Session"); return con; } diff --git a/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java index 9aed389b63..2dc5bed95e 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java @@ -60,6 +60,7 @@ import org.springframework.oxm.ValidationFailureException; import org.springframework.oxm.XmlMappingException; import org.springframework.oxm.support.AbstractMarshaller; import org.springframework.oxm.support.SaxResourceUtils; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.xml.DomUtils; import org.springframework.util.xml.StaxUtils; @@ -94,12 +95,15 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing public static final String DEFAULT_ENCODING = "UTF-8"; + @Nullable private Resource[] mappingLocations; private String encoding = DEFAULT_ENCODING; + @Nullable private Class[] targetClasses; + @Nullable private String[] targetPackages; private boolean validating = false; @@ -112,10 +116,13 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing private boolean marshalExtendedType = true; + @Nullable private String rootElement; + @Nullable private String noNamespaceSchemaLocation; + @Nullable private String schemaLocation; private boolean useXSITypeAtRoot = false; @@ -126,32 +133,44 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing private boolean ignoreExtraElements = false; + @Nullable private Object rootObject; private boolean reuseObjects = false; private boolean clearCollections = false; + @Nullable private Map castorProperties; + @Nullable private Map doctypes; + @Nullable private Map processingInstructions; + @Nullable private Map namespaceMappings; + @Nullable private Map namespaceToPackageMapping; + @Nullable private EntityResolver entityResolver; + @Nullable private XMLClassDescriptorResolver classDescriptorResolver; + @Nullable private IDResolver idResolver; + @Nullable private ObjectFactory objectFactory; + @Nullable private ClassLoader beanClassLoader; + @Nullable private XMLContext xmlContext; @@ -456,8 +475,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing * @see XMLContext#addMapping(org.exolab.castor.mapping.Mapping) * @see XMLContext#addClass(Class) */ - protected XMLContext createXMLContext(Resource[] mappingLocations, Class[] targetClasses, - String[] targetPackages) throws MappingException, ResolverException, IOException { + protected XMLContext createXMLContext(@Nullable Resource[] mappingLocations, + @Nullable Class[] targetClasses, @Nullable String[] targetPackages) + throws MappingException, ResolverException, IOException { XMLContext context = new XMLContext(); if (!ObjectUtils.isEmpty(mappingLocations)) { @@ -520,7 +540,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, @Nullable LexicalHandler lexicalHandler) throws XmlMappingException { - Marshaller marshaller = xmlContext.createMarshaller(); + Assert.state(this.xmlContext != null, "CastorMarshaller not initialized"); + Marshaller marshaller = this.xmlContext.createMarshaller(); marshaller.setContentHandler(contentHandler); doMarshal(graph, marshaller); } @@ -532,7 +553,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing @Override protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException { - Marshaller marshaller = xmlContext.createMarshaller(); + Assert.state(this.xmlContext != null, "CastorMarshaller not initialized"); + Marshaller marshaller = this.xmlContext.createMarshaller(); marshaller.setWriter(writer); doMarshal(graph, marshaller); } @@ -641,6 +663,7 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } private Unmarshaller createUnmarshaller() { + Assert.state(this.xmlContext != null, "CastorMarshaller not initialized"); Unmarshaller unmarshaller = this.xmlContext.createUnmarshaller(); customizeUnmarshaller(unmarshaller); return unmarshaller; diff --git a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java index ff4f92e2cd..f1e0396b3f 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/ClassPathJaxb2TypeScanner.java @@ -33,6 +33,7 @@ import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.core.type.filter.TypeFilter; +import org.springframework.lang.Nullable; import org.springframework.oxm.UncategorizedMappingException; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -64,7 +65,7 @@ class ClassPathJaxb2TypeScanner { private final String[] packagesToScan; - public ClassPathJaxb2TypeScanner(ClassLoader classLoader, String... packagesToScan) { + public ClassPathJaxb2TypeScanner(@Nullable ClassLoader classLoader, String... packagesToScan) { Assert.notEmpty(packagesToScan, "'packagesToScan' must not be empty"); this.resourcePatternResolver = new PathMatchingResourcePatternResolver(classLoader); this.packagesToScan = packagesToScan; diff --git a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java index 1a77c47df4..447e822125 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java @@ -131,30 +131,42 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private String contextPath; + @Nullable private Class[] classesToBeBound; + @Nullable private String[] packagesToScan; + @Nullable private Map jaxbContextProperties; + @Nullable private Map marshallerProperties; + @Nullable private Map unmarshallerProperties; + @Nullable private Marshaller.Listener marshallerListener; + @Nullable private Unmarshaller.Listener unmarshallerListener; + @Nullable private ValidationEventHandler validationEventHandler; + @Nullable private XmlAdapter[] adapters; + @Nullable private Resource[] schemaResources; private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI; + @Nullable private LSResourceResolver schemaResourceResolver; private boolean lazyInit = false; @@ -165,14 +177,18 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi private boolean checkForXmlRootElement = true; + @Nullable private Class mappedClass; + @Nullable private ClassLoader beanClassLoader; private final Object jaxbContextMonitor = new Object(); + @Nullable private volatile JAXBContext jaxbContext; + @Nullable private Schema schema; private boolean supportDtd = false; @@ -202,6 +218,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi /** * Return the JAXB context path. */ + @Nullable public String getContextPath() { return this.contextPath; } @@ -219,6 +236,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi /** * Return the list of Java classes to be recognized by a newly created JAXBContext. */ + @Nullable public Class[] getClassesToBeBound() { return this.classesToBeBound; } @@ -237,6 +255,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi /** * Return the packages to search for JAXB2 annotations. */ + @Nullable public String[] getPackagesToScan() { return this.packagesToScan; } @@ -464,27 +483,33 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi * Return the JAXBContext used by this marshaller, lazily building it if necessary. */ public JAXBContext getJaxbContext() { - if (this.jaxbContext != null) { - return this.jaxbContext; + JAXBContext context = this.jaxbContext; + if (context != null) { + return context; } synchronized (this.jaxbContextMonitor) { - if (this.jaxbContext == null) { + context = this.jaxbContext; + if (context == null) { try { if (StringUtils.hasLength(this.contextPath)) { - this.jaxbContext = createJaxbContextFromContextPath(); + context = createJaxbContextFromContextPath(); } else if (!ObjectUtils.isEmpty(this.classesToBeBound)) { - this.jaxbContext = createJaxbContextFromClasses(); + context = createJaxbContextFromClasses(this.classesToBeBound); } else if (!ObjectUtils.isEmpty(this.packagesToScan)) { - this.jaxbContext = createJaxbContextFromPackages(); + context = createJaxbContextFromPackages(this.packagesToScan); } + else { + context = JAXBContext.newInstance(); + } + this.jaxbContext = context; } catch (JAXBException ex) { throw convertJaxbException(ex); } } - return this.jaxbContext; + return context; } } @@ -512,25 +537,25 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi } } - private JAXBContext createJaxbContextFromClasses() throws JAXBException { + private JAXBContext createJaxbContextFromClasses(Class... classesToBeBound) throws JAXBException { if (logger.isInfoEnabled()) { logger.info("Creating JAXBContext with classes to be bound [" + - StringUtils.arrayToCommaDelimitedString(this.classesToBeBound) + "]"); + StringUtils.arrayToCommaDelimitedString(classesToBeBound) + "]"); } if (this.jaxbContextProperties != null) { - return JAXBContext.newInstance(this.classesToBeBound, this.jaxbContextProperties); + return JAXBContext.newInstance(classesToBeBound, this.jaxbContextProperties); } else { - return JAXBContext.newInstance(this.classesToBeBound); + return JAXBContext.newInstance(classesToBeBound); } } - private JAXBContext createJaxbContextFromPackages() throws JAXBException { + private JAXBContext createJaxbContextFromPackages(String... packagesToScan) throws JAXBException { if (logger.isInfoEnabled()) { logger.info("Creating JAXBContext by scanning packages [" + - StringUtils.arrayToCommaDelimitedString(this.packagesToScan) + "]"); + StringUtils.arrayToCommaDelimitedString(packagesToScan) + "]"); } - ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.beanClassLoader, this.packagesToScan); + ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.beanClassLoader, packagesToScan); Class[] jaxb2Classes = scanner.scanPackages(); if (logger.isDebugEnabled()) { logger.debug("Found JAXB2 classes: [" + StringUtils.arrayToCommaDelimitedString(jaxb2Classes) + "]"); diff --git a/spring-oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java index 03ef939a60..578cc2a2e3 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java @@ -87,26 +87,35 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe private static final String DEFAULT_BINDING_NAME = "binding"; + @Nullable private Class targetClass; + @Nullable private String targetPackage; + @Nullable private String bindingName; private int indent = -1; private String encoding = "UTF-8"; + @Nullable private Boolean standalone; + @Nullable private String docTypeRootElementName; + @Nullable private String docTypeSystemId; + @Nullable private String docTypePublicId; + @Nullable private String docTypeInternalSubset; + @Nullable private IBindingFactory bindingFactory; private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); @@ -241,6 +250,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe if (this.targetClass != null) { return (this.targetClass == clazz); } + Assert.state(this.bindingFactory != null, "JibxMarshaller not initialized"); String[] mappedClasses = this.bindingFactory.getMappedClasses(); String className = clazz.getName(); for (String mappedClass : mappedClasses) { @@ -443,6 +453,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe * @throws JiBXException in case of errors */ protected IMarshallingContext createMarshallingContext() throws JiBXException { + Assert.state(this.bindingFactory != null, "JibxMarshaller not initialized"); IMarshallingContext marshallingContext = this.bindingFactory.createMarshallingContext(); marshallingContext.setIndent(this.indent); return marshallingContext; @@ -454,6 +465,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe * @throws JiBXException in case of errors */ protected IUnmarshallingContext createUnmarshallingContext() throws JiBXException { + Assert.state(this.bindingFactory != null, "JibxMarshaller not initialized"); return this.bindingFactory.createUnmarshallingContext(); } diff --git a/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java index 918a58d772..61e59ee54e 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java @@ -77,6 +77,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { private boolean processExternalEntities = false; + @Nullable private DocumentBuilderFactory documentBuilderFactory; private final Object documentBuilderFactoryMonitor = new Object(); diff --git a/spring-oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java index 8e3531684d..5eda7ea5d4 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java @@ -122,40 +122,56 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo public static final String DEFAULT_ENCODING = "UTF-8"; + @Nullable private ReflectionProvider reflectionProvider; + @Nullable private HierarchicalStreamDriver streamDriver; + @Nullable private HierarchicalStreamDriver defaultDriver; + @Nullable private Mapper mapper; + @Nullable private Class[] mapperWrappers; private ConverterLookup converterLookup = new DefaultConverterLookup(); private ConverterRegistry converterRegistry = (ConverterRegistry) this.converterLookup; + @Nullable private ConverterMatcher[] converters; + @Nullable private MarshallingStrategy marshallingStrategy; + @Nullable private Integer mode; + @Nullable private Map aliases; + @Nullable private Map aliasesByType; + @Nullable private Map fieldAliases; + @Nullable private Class[] useAttributeForTypes; + @Nullable private Map useAttributeFor; + @Nullable private Map, String> implicitCollections; + @Nullable private Map, String> omittedFields; + @Nullable private Class[] annotatedClasses; private boolean autodetectAnnotations; @@ -164,10 +180,12 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo private NameCoder nameCoder = new XmlFriendlyNameCoder(); + @Nullable private Class[] supportedClasses; private ClassLoader beanClassLoader = new CompositeClassLoader(); + @Nullable private XStream xstream; diff --git a/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java b/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java index 0c614524b0..91dfe0a54e 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/http/client/MockClientHttpRequest.java @@ -18,11 +18,14 @@ package org.springframework.mock.http.client; import java.io.IOException; import java.net.URI; +import java.net.URISyntaxException; import org.springframework.http.HttpMethod; import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.Nullable; import org.springframework.mock.http.MockHttpOutputMessage; +import org.springframework.util.Assert; /** * Mock implementation of {@link ClientHttpRequest}. @@ -37,6 +40,7 @@ public class MockClientHttpRequest extends MockHttpOutputMessage implements Clie private URI uri; + @Nullable private ClientHttpResponse clientHttpResponse; private boolean executed = false; @@ -46,6 +50,13 @@ public class MockClientHttpRequest extends MockHttpOutputMessage implements Clie * Default constructor. */ public MockClientHttpRequest() { + this.httpMethod = HttpMethod.GET; + try { + this.uri = new URI("/"); + } + catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } } /** @@ -106,6 +117,7 @@ public class MockClientHttpRequest extends MockHttpOutputMessage implements Clie * potentially different than the configured response. */ protected ClientHttpResponse executeInternal() throws IOException { + Assert.state(this.clientHttpResponse != null, "No ClientHttpResponse"); return this.clientHttpResponse; } @@ -113,12 +125,8 @@ public class MockClientHttpRequest extends MockHttpOutputMessage implements Clie @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (this.httpMethod != null) { - sb.append(this.httpMethod); - } - if (this.uri != null) { - sb.append(" ").append(this.uri); - } + sb.append(this.httpMethod); + sb.append(" ").append(this.uri); if (!getHeaders().isEmpty()) { sb.append(", headers: ").append(getHeaders()); } 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 5668094d16..709409bcdf 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 @@ -84,6 +84,7 @@ import org.springframework.util.ReflectionUtils; public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder { /** An instance of this class bound to JNDI */ + @Nullable private static volatile SimpleNamingContextBuilder activated; private static boolean initialized = false; @@ -111,17 +112,18 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder * to control JNDI bindings */ public static SimpleNamingContextBuilder emptyActivatedContextBuilder() throws NamingException { - if (activated != null) { + SimpleNamingContextBuilder builder = activated; + if (builder != null) { // Clear already activated context builder. - activated.clear(); + builder.clear(); } else { // Create and activate new context builder. - SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); + builder = new SimpleNamingContextBuilder(); // The activate() call will cause an assignment to the activated variable. builder.activate(); } - return activated; + return builder; } 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 a85dc2dd3c..c36c67e9af 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 @@ -44,10 +44,12 @@ public class MockAsyncContext implements AsyncContext { private final HttpServletRequest request; + @Nullable private final HttpServletResponse response; private final List listeners = new ArrayList<>(); + @Nullable private String dispatchedPath; private long timeout = 10 * 1000L; // 10 seconds is Tomcat's default @@ -72,6 +74,7 @@ public class MockAsyncContext implements AsyncContext { } @Override + @Nullable public ServletResponse getResponse() { return this.response; } @@ -99,6 +102,7 @@ public class MockAsyncContext implements AsyncContext { } } + @Nullable public String getDispatchedPath() { return this.dispatchedPath; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java b/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java index 1f2f775254..b3a04d1565 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java @@ -29,6 +29,7 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -43,19 +44,21 @@ import org.springframework.util.ObjectUtils; * @author Juergen Hoeller * @author Rob Winch * @author Rossen Stoyanchev - * * @since 2.0.3 * @see MockFilterConfig * @see PassThroughFilterChain */ public class MockFilterChain implements FilterChain { + @Nullable private ServletRequest request; + @Nullable private ServletResponse response; private final List filters; + @Nullable private Iterator iterator; @@ -70,7 +73,6 @@ public class MockFilterChain implements FilterChain { /** * Create a FilterChain with a Servlet. - * * @param servlet the Servlet to invoke * @since 3.2 */ @@ -80,7 +82,6 @@ public class MockFilterChain implements FilterChain { /** * Create a {@code FilterChain} with Filter's and a Servlet. - * * @param servlet the {@link Servlet} to invoke in this {@link FilterChain} * @param filters the {@link Filter}'s to invoke in this {@link FilterChain} * @since 3.2 @@ -96,9 +97,11 @@ public class MockFilterChain implements FilterChain { return Arrays.asList(allFilters); } + /** * Return the request that {@link #doFilter} has been called with. */ + @Nullable public ServletRequest getRequest() { return this.request; } @@ -106,6 +109,7 @@ public class MockFilterChain implements FilterChain { /** * Return the response that {@link #doFilter} has been called with. */ + @Nullable public ServletResponse getResponse() { return this.response; } 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 b6c2f7a842..fcd1c72d7e 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 @@ -169,10 +169,13 @@ public class MockHttpServletRequest implements HttpServletRequest { private final Map attributes = new LinkedHashMap<>(); + @Nullable private String characterEncoding; + @Nullable private byte[] content; + @Nullable private String contentType; private final Map parameters = new LinkedHashMap<>(16); @@ -206,6 +209,7 @@ public class MockHttpServletRequest implements HttpServletRequest { private boolean asyncSupported = false; + @Nullable private MockAsyncContext asyncContext; private DispatcherType dispatcherType = DispatcherType.REQUEST; @@ -215,32 +219,42 @@ public class MockHttpServletRequest implements HttpServletRequest { // HttpServletRequest properties // --------------------------------------------------------------------- + @Nullable private String authType; + @Nullable private Cookie[] cookies; private final Map headers = new LinkedCaseInsensitiveMap<>(); + @Nullable private String method; + @Nullable private String pathInfo; private String contextPath = ""; + @Nullable private String queryString; + @Nullable private String remoteUser; private final Set userRoles = new HashSet<>(); + @Nullable private Principal userPrincipal; + @Nullable private String requestedSessionId; + @Nullable private String requestURI; private String servletPath = ""; + @Nullable private HttpSession session; private boolean requestedSessionIdValid = true; @@ -376,7 +390,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override - public void setCharacterEncoding(String characterEncoding) { + public void setCharacterEncoding(@Nullable String characterEncoding) { this.characterEncoding = characterEncoding; updateContentTypeHeader(); } @@ -401,13 +415,13 @@ public class MockHttpServletRequest implements HttpServletRequest { * @see #getContentAsByteArray() * @see #getContentAsString() */ - public void setContent(byte[] content) { + public void setContent(@Nullable byte[] content) { this.content = content; } /** * Get the content of the request body as a byte array. - * @return the content as a byte array, potentially {@code null} + * @return the content as a byte array (potentially {@code null}) * @since 5.0 * @see #setContent(byte[]) * @see #getContentAsString() @@ -932,6 +946,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getAuthType() { return this.authType; } @@ -1092,6 +1107,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getMethod() { return this.method; } @@ -1101,6 +1117,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getPathInfo() { return this.pathInfo; } @@ -1125,6 +1142,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getQueryString() { return this.queryString; } @@ -1134,6 +1152,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getRemoteUser() { return this.remoteUser; } @@ -1153,6 +1172,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public Principal getUserPrincipal() { return this.userPrincipal; } @@ -1162,6 +1182,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getRequestedSessionId() { return this.requestedSessionId; } @@ -1171,6 +1192,7 @@ public class MockHttpServletRequest implements HttpServletRequest { } @Override + @Nullable public String getRequestURI() { return this.requestURI; } 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 4fcec47e8e..928fb9e7c9 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 @@ -72,6 +72,7 @@ public class MockHttpServletResponse implements HttpServletResponse { private boolean writerAccessAllowed = true; + @Nullable private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; private boolean charset = false; @@ -80,10 +81,12 @@ public class MockHttpServletResponse implements HttpServletResponse { private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content); + @Nullable private PrintWriter writer; private long contentLength = 0; + @Nullable private String contentType; private int bufferSize = 4096; @@ -103,8 +106,10 @@ public class MockHttpServletResponse implements HttpServletResponse { private int status = HttpServletResponse.SC_OK; + @Nullable private String errorMessage; + @Nullable private String forwardedUrl; private final List includedUrls = new ArrayList<>(); @@ -295,7 +300,7 @@ public class MockHttpServletResponse implements HttpServletResponse { this.characterEncoding = null; this.contentLength = 0; this.contentType = null; - this.locale = null; + this.locale = Locale.getDefault(); this.cookies.clear(); this.headers.clear(); this.status = HttpServletResponse.SC_OK; @@ -303,11 +308,9 @@ public class MockHttpServletResponse implements HttpServletResponse { } @Override - public void setLocale(@Nullable Locale locale) { + public void setLocale(Locale locale) { this.locale = locale; - if (locale != null) { - doAddHeaderValue(HttpHeaders.ACCEPT_LANGUAGE, locale.toLanguageTag(), true); - } + doAddHeaderValue(HttpHeaders.ACCEPT_LANGUAGE, locale.toLanguageTag(), true); } @Override @@ -585,7 +588,7 @@ public class MockHttpServletResponse implements HttpServletResponse { HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.ACCEPT_LANGUAGE, value.toString()); List locales = headers.getAcceptLanguageAsLocales(); - setLocale(locales.isEmpty() ? null : locales.get(0)); + this.locale = (!locales.isEmpty() ? locales.get(0) : Locale.getDefault()); return true; } else { @@ -629,6 +632,7 @@ public class MockHttpServletResponse implements HttpServletResponse { return this.status; } + @Nullable public String getErrorMessage() { return this.errorMessage; } 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 6e5d47c2ae..2bf39e3c5a 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 @@ -35,6 +35,7 @@ public class MockJspWriter extends JspWriter { private final HttpServletResponse response; + @Nullable private PrintWriter targetWriter; 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 902940e581..1e2fdb5e2a 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 @@ -44,6 +44,7 @@ public class MockMultipartFile implements MultipartFile { private String originalFilename; + @Nullable private String contentType; private final byte[] content; @@ -111,6 +112,7 @@ public class MockMultipartFile implements MultipartFile { } @Override + @Nullable public String getContentType() { return this.contentType; } 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 37f4071030..2ccaee4697 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 @@ -62,6 +62,7 @@ public class MockPageContext extends PageContext { private final Map attributes = new LinkedHashMap<>(); + @Nullable private JspWriter out; 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 716cb99a7b..67dfd43a06 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 @@ -39,6 +39,7 @@ public class MockPart implements Part { private final String name; + @Nullable private final String filename; private final byte[] content; @@ -79,6 +80,7 @@ public class MockPart implements Part { } @Override + @Nullable public String getSubmittedFileName() { return this.filename; } 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 3cf048f50a..2c99c661ff 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 @@ -29,7 +29,6 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; - import javax.servlet.Filter; import javax.servlet.FilterRegistration; import javax.servlet.RequestDispatcher; @@ -131,14 +130,17 @@ public class MockServletContext implements ServletContext { private final Set declaredRoles = new LinkedHashSet<>(); + @Nullable private Set sessionTrackingModes; private final SessionCookieConfig sessionCookieConfig = new MockSessionCookieConfig(); private int sessionTimeout; + @Nullable private String requestCharacterEncoding; + @Nullable private String responseCharacterEncoding; private final Map mimeTypes = new LinkedHashMap<>(); @@ -585,6 +587,7 @@ public class MockServletContext implements ServletContext { } // @Override - but only against Servlet 4.0 + @Nullable public String getRequestCharacterEncoding() { return this.requestCharacterEncoding; } @@ -595,6 +598,7 @@ public class MockServletContext implements ServletContext { } // @Override - but only against Servlet 4.0 + @Nullable public String getResponseCharacterEncoding() { return this.responseCharacterEncoding; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/PassThroughFilterChain.java b/spring-test/src/main/java/org/springframework/mock/web/PassThroughFilterChain.java index 080b8534ea..647600f212 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/PassThroughFilterChain.java +++ b/spring-test/src/main/java/org/springframework/mock/web/PassThroughFilterChain.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. @@ -24,6 +24,7 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -40,10 +41,13 @@ import org.springframework.util.Assert; */ public class PassThroughFilterChain implements FilterChain { + @Nullable private Filter filter; + @Nullable private FilterChain nextFilterChain; + @Nullable private Servlet servlet; @@ -79,6 +83,7 @@ public class PassThroughFilterChain implements FilterChain { this.filter.doFilter(request, response, this.nextFilterChain); } else { + Assert.state(this.servlet != null, "Neither a Filter not a Servlet set"); this.servlet.service(request, response); } } 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 4a10360871..c6f0d361ad 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 @@ -59,6 +59,7 @@ public class MockServerRequest implements ServerRequest { private final MockHeaders headers; + @Nullable private final Object body; private final Map attributes; @@ -67,14 +68,16 @@ public class MockServerRequest implements ServerRequest { private final Map pathVariables; + @Nullable private final WebSession session; + @Nullable private Principal principal; private MockServerRequest(HttpMethod method, URI uri, MockHeaders headers, @Nullable Object body, Map attributes, MultiValueMap queryParams, - Map pathVariables, WebSession session, Principal principal) { + Map pathVariables, @Nullable WebSession session, @Nullable Principal principal) { this.method = method; this.uri = uri; @@ -209,6 +212,7 @@ public class MockServerRequest implements ServerRequest { private MockHeaders headers = new MockHeaders(new HttpHeaders()); + @Nullable private Object body; private Map attributes = new ConcurrentHashMap<>(); @@ -217,8 +221,10 @@ public class MockServerRequest implements ServerRequest { private Map pathVariables = new LinkedHashMap<>(); + @Nullable private WebSession session; + @Nullable private Principal principal; @Override 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 e18e52d833..01cde42d30 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 @@ -51,9 +51,9 @@ public class ContextConfigurationAttributes { private final Class declaringClass; - private Class[] classes; + private Class[] classes = new Class[0]; - private String[] locations; + private String[] locations = new String[0]; private final boolean inheritLocations; @@ -61,6 +61,7 @@ public class ContextConfigurationAttributes { private final boolean inheritInitializers; + @Nullable private final String name; private final Class contextLoaderClass; @@ -204,7 +205,7 @@ public class ContextConfigurationAttributes { * @see #setClasses(Class[]) */ public Class[] getClasses() { - return (this.classes != null ? this.classes : new Class[0]); + return this.classes; } /** @@ -215,7 +216,7 @@ public class ContextConfigurationAttributes { * @see #hasLocations() */ public boolean hasClasses() { - return !ObjectUtils.isEmpty(getClasses()); + return (getClasses().length > 0); } /** @@ -239,7 +240,7 @@ public class ContextConfigurationAttributes { * @see #setLocations */ public String[] getLocations() { - return (this.locations != null ? this.locations : new String[0]); + return this.locations; } /** @@ -250,7 +251,7 @@ public class ContextConfigurationAttributes { * @see #hasClasses() */ public boolean hasLocations() { - return !ObjectUtils.isEmpty(getLocations()); + return (getLocations().length > 0); } /** 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 23e4290e94..f40d14da3c 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 @@ -96,8 +96,10 @@ public class MergedContextConfiguration implements Serializable { private final ContextLoader contextLoader; + @Nullable private final CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate; + @Nullable private final MergedContextConfiguration parent; 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 30749f1a6d..f8f25d4b15 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 @@ -104,10 +104,11 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner { Assert.state(ClassUtils.isPresent("org.junit.internal.Throwables", SpringJUnit4ClassRunner.class.getClassLoader()), "SpringJUnit4ClassRunner requires JUnit 4.12 or higher."); - withRulesMethod = ReflectionUtils.findMethod(SpringJUnit4ClassRunner.class, "withRules", + Method method = ReflectionUtils.findMethod(SpringJUnit4ClassRunner.class, "withRules", FrameworkMethod.class, Object.class, Statement.class); - Assert.state(withRulesMethod != null, "SpringJUnit4ClassRunner requires JUnit 4.12 or higher"); - ReflectionUtils.makeAccessible(withRulesMethod); + Assert.state(method != null, "SpringJUnit4ClassRunner requires JUnit 4.12 or higher"); + ReflectionUtils.makeAccessible(method); + withRulesMethod = method; } diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/ProfileValueChecker.java b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/ProfileValueChecker.java index b665142001..ea5f03c72f 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/ProfileValueChecker.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/ProfileValueChecker.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. @@ -46,6 +46,7 @@ public class ProfileValueChecker extends Statement { private final Class testClass; + @Nullable private final Method testMethod; 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 4aca49c0ce..b383cd695b 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 @@ -50,10 +50,13 @@ public class DefaultTestContext implements TestContext { private final Class testClass; + @Nullable private volatile Object testInstance; + @Nullable private volatile Method testMethod; + @Nullable private volatile Throwable testException; @@ -133,15 +136,18 @@ public class DefaultTestContext implements TestContext { } public final Object getTestInstance() { - Assert.state(this.testInstance != null, "No test instance"); - return this.testInstance; + Object testInstance = this.testInstance; + Assert.state(testInstance != null, "No test instance"); + return testInstance; } public final Method getTestMethod() { - Assert.state(this.testMethod != null, "No test method"); - return this.testMethod; + Method testMethod = this.testMethod; + Assert.state(testMethod != null, "No test method"); + return testMethod; } + @Nullable public final Throwable getTestException() { return this.testException; } diff --git a/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java b/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java index 01b6bd93d2..8f5cdda1b1 100644 --- a/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java +++ b/spring-test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.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. @@ -21,6 +21,13 @@ import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.testng.IHookCallBack; +import org.testng.IHookable; +import org.testng.ITestResult; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -34,14 +41,6 @@ import org.springframework.test.context.support.DirtiesContextBeforeModesTestExe import org.springframework.test.context.support.DirtiesContextTestExecutionListener; import org.springframework.test.context.web.ServletTestExecutionListener; -import org.testng.IHookCallBack; -import org.testng.IHookable; -import org.testng.ITestResult; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; - /** * Abstract base test class which integrates the Spring TestContext Framework * with explicit {@link ApplicationContext} testing support in a TestNG @@ -96,10 +95,12 @@ public abstract class AbstractTestNGSpringContextTests implements IHookable, App * The {@link ApplicationContext} that was injected into this test instance * via {@link #setApplicationContext(ApplicationContext)}. */ + @Nullable protected ApplicationContext applicationContext; private final TestContextManager testContextManager; + @Nullable private Throwable testException; 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 ef1df23a1d..79a7147099 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 @@ -188,6 +188,7 @@ public abstract class AbstractTransactionalTestNGSpringContextTests extends Abst protected void executeSqlScript(String sqlResourcePath, boolean continueOnError) throws DataAccessException { DataSource ds = this.jdbcTemplate.getDataSource(); Assert.state(ds != null, "No DataSource set"); + Assert.state(this.applicationContext != null, "No ApplicationContext available"); Resource resource = this.applicationContext.getResource(sqlResourcePath); 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 668ff8347f..8dba93e8b9 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 @@ -50,6 +50,7 @@ class TransactionContext { private boolean flaggedForRollback; + @Nullable private TransactionStatus transactionStatus; private volatile int transactionsStarted = 0; 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 ad7b10dfa6..ec6c7a052e 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 @@ -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. @@ -307,7 +307,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis * @see #getTransactionManager(TestContext) */ @Nullable - protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) { + protected PlatformTransactionManager getTransactionManager(TestContext testContext, @Nullable String qualifier) { // Look up by type and qualifier from @Transactional if (StringUtils.hasText(qualifier)) { try { 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 a627cb5c34..71ed086b8d 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 @@ -287,6 +287,7 @@ public abstract class MetaAnnotationUtils { private final Class declaringClass; + @Nullable private final Annotation composedAnnotation; private final T annotation; @@ -306,8 +307,10 @@ public abstract class MetaAnnotationUtils { this.declaringClass = declaringClass; this.composedAnnotation = composedAnnotation; this.annotation = annotation; - this.annotationAttributes = AnnotatedElementUtils.findMergedAnnotationAttributes( + AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( rootDeclaringClass, annotation.annotationType().getName(), false, false); + Assert.state(attributes != null, "No annotation attributes"); + this.annotationAttributes = attributes; } public Class getRootDeclaringClass() { @@ -345,6 +348,7 @@ public abstract class MetaAnnotationUtils { return this.annotationAttributes; } + @Nullable public Annotation getComposedAnnotation() { return this.composedAnnotation; } diff --git a/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java b/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java index 9000b1cb00..ce8fea41e4 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java @@ -23,6 +23,7 @@ import org.springframework.http.HttpMethod; import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.client.RestTemplate; import org.springframework.web.client.support.RestGatewaySupport; @@ -210,8 +211,10 @@ public class MockRestServiceServer { private static class DefaultBuilder implements MockRestServiceServerBuilder { + @Nullable private final RestTemplate restTemplate; + @Nullable private final org.springframework.web.client.AsyncRestTemplate asyncRestTemplate; private boolean ignoreExpectOrder; diff --git a/spring-test/src/main/java/org/springframework/test/web/client/SimpleRequestExpectationManager.java b/spring-test/src/main/java/org/springframework/test/web/client/SimpleRequestExpectationManager.java index f76449e398..ec0b1fdae0 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/SimpleRequestExpectationManager.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/SimpleRequestExpectationManager.java @@ -21,6 +21,7 @@ import java.util.Iterator; import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -37,6 +38,7 @@ import org.springframework.util.Assert; */ public class SimpleRequestExpectationManager extends AbstractRequestExpectationManager { + @Nullable private Iterator expectationIterator; private final RequestExpectationGroup repeatExpectations = new RequestExpectationGroup(); @@ -52,7 +54,7 @@ public class SimpleRequestExpectationManager extends AbstractRequestExpectationM public ClientHttpResponse validateRequestInternal(ClientHttpRequest request) throws IOException { RequestExpectation expectation = this.repeatExpectations.findExpectation(request); if (expectation == null) { - if (!this.expectationIterator.hasNext()) { + if (this.expectationIterator == null || !this.expectationIterator.hasNext()) { throw createUnexpectedRequestError(request); } expectation = this.expectationIterator.next(); diff --git a/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java b/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java index 7a5be4d137..d2b5a4d5b3 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java @@ -44,6 +44,7 @@ public class DefaultResponseCreator implements ResponseCreator { private byte[] content = new byte[0]; + @Nullable private Resource contentResource; private final HttpHeaders headers = new HttpHeaders(); diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultControllerSpec.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultControllerSpec.java index b9c0cba3bf..d1f41c2b08 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultControllerSpec.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultControllerSpec.java @@ -25,6 +25,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.format.FormatterRegistry; import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.validation.Validator; @@ -138,23 +139,30 @@ class DefaultControllerSpec extends AbstractMockServerSpec contentTypeResolverConsumer; + @Nullable private Consumer corsRegistryConsumer; + @Nullable private Consumer argumentResolverConsumer; + @Nullable private Consumer pathMatchConsumer; + @Nullable private Consumer messageCodecsConsumer; + @Nullable private Consumer formattersConsumer; + @Nullable private Validator validator; + @Nullable private Consumer viewResolversConsumer; - @Override public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) { if (this.contentTypeResolverConsumer != null) { @@ -198,6 +206,7 @@ class DefaultControllerSpec extends AbstractMockServerSpec mono) { ClientResponse clientResponse = mono.block(getTimeout()); + Assert.state(clientResponse != null, "No ClientResponse"); ExchangeResult exchangeResult = wiretapConnector.claimRequest(this.requestId); return new DefaultResponseSpec(exchangeResult, clientResponse, this.uriTemplate, getTimeout()); } @@ -283,7 +284,7 @@ class DefaultWebTestClient implements WebTestClient { private final Duration timeout; UndecodedExchangeResult(ExchangeResult result, ClientResponse response, - String uriTemplate, Duration timeout) { + @Nullable String uriTemplate, Duration timeout) { super(result, uriTemplate); this.response = response; @@ -318,7 +319,9 @@ class DefaultWebTestClient implements WebTestClient { private final UndecodedExchangeResult result; - DefaultResponseSpec(ExchangeResult result, ClientResponse response, String uriTemplate, Duration timeout) { + DefaultResponseSpec( + ExchangeResult result, ClientResponse response, @Nullable String uriTemplate, Duration timeout) { + this.result = new UndecodedExchangeResult(result, response, uriTemplate, timeout); } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java index e6b0462905..e095d19917 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java @@ -42,10 +42,13 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder { private final WebClient.Builder webClientBuilder; + @Nullable private final WebHttpHandlerBuilder httpHandlerBuilder; + @Nullable private final ClientHttpConnector connector; + @Nullable private Duration responseTimeout; @@ -58,11 +61,10 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder { } DefaultWebTestClientBuilder(@Nullable WebClient.Builder webClientBuilder, - @Nullable WebHttpHandlerBuilder httpHandlerBuilder, - @Nullable ClientHttpConnector connector, + @Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector, @Nullable Duration responseTimeout) { - Assert.isTrue(httpHandlerBuilder != null || connector !=null, + Assert.isTrue(httpHandlerBuilder != null || connector != null, "Either WebHttpHandlerBuilder or ClientHttpConnector must be provided"); this.webClientBuilder = (webClientBuilder != null ? webClientBuilder : WebClient.builder()); @@ -139,11 +141,14 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder { return this; } + @Override public WebTestClient build() { - - ClientHttpConnector connectorToUse = (this.connector != null ? this.connector : - new HttpHandlerConnector(this.httpHandlerBuilder.build())); + ClientHttpConnector connectorToUse = this.connector; + if (connectorToUse == null) { + Assert.state(this.httpHandlerBuilder != null, "No WebHttpHandlerBuilder available"); + connectorToUse = new HttpHandlerConnector(this.httpHandlerBuilder.build()); + } DefaultWebTestClientBuilder webTestClientBuilder = new DefaultWebTestClientBuilder( this.webClientBuilder.clone(), this.httpHandlerBuilder, 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 a29c55d9f2..88065cdee4 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 @@ -29,6 +29,7 @@ import org.springframework.lang.Nullable; */ public class EntityExchangeResult extends ExchangeResult { + @Nullable private final T 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 1f6bf9b55c..e8036e6b9e 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 @@ -34,6 +34,7 @@ import org.springframework.http.ResponseCookie; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; +import org.springframework.util.ObjectUtils; /** * Container for request and response details for exchanges performed through @@ -61,6 +62,7 @@ public class ExchangeResult { private final WiretapClientHttpResponse response; + @Nullable private final String uriTemplate; @@ -78,7 +80,7 @@ public class ExchangeResult { * Constructor to copy the from the yet undecoded ExchangeResult with extra * information to expose such as the original URI template used, if any. */ - ExchangeResult(ExchangeResult other, String uriTemplate) { + ExchangeResult(ExchangeResult other, @Nullable String uriTemplate) { this.request = other.request; this.response = other.response; this.uriTemplate = uriTemplate; @@ -127,6 +129,7 @@ public class ExchangeResult { * Return the raw request body content written as a {@code byte[]}. * @throws IllegalStateException if the request body is not fully written yet. */ + @Nullable public byte[] getRequestBodyContent() { MonoProcessor body = this.request.getRecordedContent(); Assert.isTrue(body.isTerminated(), "Request body incomplete."); @@ -159,9 +162,10 @@ public class ExchangeResult { * Return the raw request body content written as a {@code byte[]}. * @throws IllegalStateException if the response is not fully read yet. */ + @Nullable public byte[] getResponseBodyContent() { MonoProcessor body = this.response.getRecordedContent(); - Assert.state(body.isTerminated(), "Response body incomplete."); + Assert.state(body.isTerminated(), "Response body incomplete"); return body.block(Duration.ZERO); } @@ -208,27 +212,23 @@ public class ExchangeResult { private String formatBody(@Nullable MediaType contentType, MonoProcessor body) { if (body.isSuccess()) { byte[] bytes = body.block(Duration.ZERO); - if (bytes.length == 0) { + if (ObjectUtils.isEmpty(bytes)) { return "No content"; } - if (contentType == null) { return "Unknown content type (" + bytes.length + " bytes)"; } - Charset charset = contentType.getCharset(); if (charset != null) { return new String(bytes, charset); } - if (PRINTABLE_MEDIA_TYPES.stream().anyMatch(contentType::isCompatibleWith)) { return new String(bytes, StandardCharsets.UTF_8); } - return "Unknown charset (" + bytes.length + " bytes)"; } else if (body.isError()) { - return "I/O failure: " + body.getError().getMessage(); + return "I/O failure: " + body.getError(); } else { return "Content not available yet"; diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/FluxExchangeResult.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/FluxExchangeResult.java index 879c5ea8fa..55e4af72aa 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/FluxExchangeResult.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/FluxExchangeResult.java @@ -90,7 +90,7 @@ public class FluxExchangeResult extends ExchangeResult { public byte[] getResponseBodyContent() { return this.body.ignoreElements() .timeout(this.timeout, Mono.error(TIMEOUT_ERROR)) - .then(Mono.defer(() -> Mono.just(super.getResponseBodyContent()))) + .then(Mono.defer(() -> Mono.justOrEmpty(super.getResponseBodyContent()))) .block(); } 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 ec16470112..00970819bc 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 @@ -42,12 +42,16 @@ class DefaultMvcResult implements MvcResult { private final MockHttpServletResponse mockResponse; + @Nullable private Object handler; + @Nullable private HandlerInterceptor[] interceptors; + @Nullable private ModelAndView modelAndView; + @Nullable private Exception resolvedException; private final AtomicReference asyncResult = new AtomicReference<>(RESULT_NONE); @@ -72,11 +76,12 @@ class DefaultMvcResult implements MvcResult { return this.mockResponse; } - public void setHandler(@Nullable Object handler) { + public void setHandler(Object handler) { this.handler = handler; } @Override + @Nullable public Object getHandler() { return this.handler; } @@ -86,6 +91,7 @@ class DefaultMvcResult implements MvcResult { } @Override + @Nullable public HandlerInterceptor[] getInterceptors() { return this.interceptors; } @@ -95,6 +101,7 @@ class DefaultMvcResult implements MvcResult { } @Override + @Nullable public Exception getResolvedException() { return this.resolvedException; } @@ -104,6 +111,7 @@ class DefaultMvcResult implements MvcResult { } @Override + @Nullable public ModelAndView getModelAndView() { return this.modelAndView; } 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 ccd719477a..8711001106 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 @@ -23,6 +23,7 @@ import javax.servlet.Filter; import javax.servlet.ServletContext; import org.springframework.beans.Mergeable; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -68,6 +69,7 @@ public final class MockMvc { private final ServletContext servletContext; + @Nullable private RequestBuilder defaultRequestBuilder; private List defaultResultMatchers = new ArrayList<>(); 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 52a796d1b6..c72efb945f 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 @@ -75,12 +75,16 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { private final WebRequest webRequest; + @Nullable private String contextPath; + @Nullable private RequestBuilder parentBuilder; + @Nullable private SmartRequestBuilder parentPostProcessor; + @Nullable private RequestPostProcessor forwardPostProcessor; diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebClientBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebClientBuilder.java index 597ac8f4f5..80b6c1ba17 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebClientBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebClientBuilder.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.htmlunit; import com.gargoylesoftware.htmlunit.WebClient; +import org.springframework.lang.Nullable; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcConfigurer; import org.springframework.util.Assert; @@ -42,6 +43,7 @@ import org.springframework.web.context.WebApplicationContext; */ public class MockMvcWebClientBuilder extends MockMvcWebConnectionBuilderSupport { + @Nullable private WebClient webClient; 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 4a4ea2c97d..743316b11b 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 @@ -87,11 +87,11 @@ public final class MockMvcWebConnection implements WebConnection { * to {@link javax.servlet.http.HttpServletRequest#getContextPath()} * which states that it can be an empty string and otherwise must start * with a "/" character and not end with a "/" character. - * @param mockMvc the {@code MockMvc} instance to use; never {@code null} - * @param webClient the {@link WebClient} to use. never {@code null} + * @param mockMvc the {@code MockMvc} instance to use (never {@code null}) + * @param webClient the {@link WebClient} to use (never {@code null}) * @param contextPath the contextPath to use */ - public MockMvcWebConnection(MockMvc mockMvc, WebClient webClient, @Nullable String contextPath) { + public MockMvcWebConnection(MockMvc mockMvc, WebClient webClient, String contextPath) { Assert.notNull(mockMvc, "MockMvc must not be null"); Assert.notNull(webClient, "WebClient must not be null"); validateContextPath(contextPath); diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionBuilderSupport.java b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionBuilderSupport.java index cb259369a6..3edf482474 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionBuilderSupport.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionBuilderSupport.java @@ -22,7 +22,6 @@ import java.util.List; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebConnection; -import org.springframework.lang.Nullable; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.htmlunit.DelegatingWebConnection.DelegateWebConnection; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @@ -93,7 +92,7 @@ public abstract class MockMvcWebConnectionBuilderSupport { + @Nullable private HtmlUnitDriver driver; private boolean javascriptEnabled = true; 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 d4a9d3d78a..cfb900bf0f 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 @@ -49,6 +49,7 @@ import org.springframework.util.Assert; 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; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; @@ -87,18 +88,25 @@ public class MockHttpServletRequestBuilder private String servletPath = ""; + @Nullable private String pathInfo = ""; + @Nullable private Boolean secure; + @Nullable private Principal principal; + @Nullable private MockHttpSession session; + @Nullable private String characterEncoding; + @Nullable private byte[] content; + @Nullable private String contentType; private final MultiValueMap headers = new LinkedMultiValueMap<>(); @@ -205,7 +213,7 @@ public class MockHttpServletRequestBuilder *

If specified, the pathInfo will be used as-is. * @see javax.servlet.http.HttpServletRequest#getPathInfo() */ - public MockHttpServletRequestBuilder pathInfo(String pathInfo) { + public MockHttpServletRequestBuilder pathInfo(@Nullable String pathInfo) { if (StringUtils.hasText(pathInfo)) { Assert.isTrue(pathInfo.startsWith("/"), "Path info must start with a '/'"); } @@ -704,7 +712,7 @@ public class MockHttpServletRequestBuilder HttpInputMessage message = new HttpInputMessage() { @Override public InputStream getBody() throws IOException { - return new ByteArrayInputStream(content); + return (content != null ? new ByteArrayInputStream(content) : StreamUtils.emptyInput()); } @Override public HttpHeaders getHeaders() { 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 437f27c8d9..9d83632dbf 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 @@ -21,6 +21,7 @@ import java.util.List; import javax.servlet.Filter; import javax.servlet.ServletContext; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockServletConfig; import org.springframework.test.web.servlet.DispatcherServletCustomizer; import org.springframework.test.web.servlet.MockMvc; @@ -53,6 +54,7 @@ public abstract class AbstractMockMvcBuilder private List filters = new ArrayList<>(); + @Nullable private RequestBuilder defaultRequestBuilder; private final List globalResultMatchers = new ArrayList<>(); diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/SharedHttpSessionConfigurer.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/SharedHttpSessionConfigurer.java index 8aedd8a021..efae692028 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/SharedHttpSessionConfigurer.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/SharedHttpSessionConfigurer.java @@ -13,10 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.test.web.servlet.setup; import javax.servlet.http.HttpSession; +import org.springframework.lang.Nullable; import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.web.context.WebApplicationContext; @@ -42,6 +44,7 @@ import org.springframework.web.context.WebApplicationContext; */ public class SharedHttpSessionConfigurer implements MockMvcConfigurer { + @Nullable private HttpSession session; 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 06b5fbd1ff..b74fefee37 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 @@ -29,6 +29,7 @@ import javax.servlet.ServletContext; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.FormattingConversionService; @@ -90,6 +91,7 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder controllers; + @Nullable private List controllerAdvice; private List> messageConverters = new ArrayList<>(); @@ -100,26 +102,34 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder mappedInterceptors = new ArrayList<>(); - private Validator validator = null; + @Nullable + private Validator validator; + @Nullable private ContentNegotiationManager contentNegotiationManager; - private FormattingConversionService conversionService = null; + @Nullable + private FormattingConversionService conversionService; + @Nullable private List handlerExceptionResolvers; + @Nullable private Long asyncRequestTimeout; + @Nullable private List viewResolvers; private LocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); - private FlashMapManager flashMapManager = null; + @Nullable + private FlashMapManager flashMapManager; private boolean useSuffixPatternMatch = true; private boolean useTrailingSlashPatternMatch = true; + @Nullable private Boolean removeSemicolonContent; private Map placeholderValues = new HashMap<>(); @@ -447,7 +457,7 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilderThis method will call CCI's {@code Interaction.execute} variant @@ -59,7 +61,9 @@ public class SimpleRecordOperation extends EisOperation { */ @Nullable public Record execute(Record inputRecord) throws DataAccessException { - return getCciTemplate().execute(getInteractionSpec(), inputRecord); + InteractionSpec interactionSpec = getInteractionSpec(); + Assert.state(interactionSpec != null, "No InteractionSpec set"); + return getCciTemplate().execute(interactionSpec, inputRecord); } /** @@ -72,7 +76,9 @@ public class SimpleRecordOperation extends EisOperation { * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record) */ public void execute(Record inputRecord, Record outputRecord) throws DataAccessException { - getCciTemplate().execute(getInteractionSpec(), inputRecord, outputRecord); + InteractionSpec interactionSpec = getInteractionSpec(); + Assert.state(interactionSpec != null, "No InteractionSpec set"); + getCciTemplate().execute(interactionSpec, inputRecord, outputRecord); } } diff --git a/spring-tx/src/main/java/org/springframework/jca/context/BootstrapContextAwareProcessor.java b/spring-tx/src/main/java/org/springframework/jca/context/BootstrapContextAwareProcessor.java index 3cc135af88..171a339e3b 100644 --- a/spring-tx/src/main/java/org/springframework/jca/context/BootstrapContextAwareProcessor.java +++ b/spring-tx/src/main/java/org/springframework/jca/context/BootstrapContextAwareProcessor.java @@ -36,6 +36,7 @@ import org.springframework.lang.Nullable; */ class BootstrapContextAwareProcessor implements BeanPostProcessor { + @Nullable private final BootstrapContext bootstrapContext; diff --git a/spring-tx/src/main/java/org/springframework/jca/endpoint/AbstractMessageEndpointFactory.java b/spring-tx/src/main/java/org/springframework/jca/endpoint/AbstractMessageEndpointFactory.java index 7934af0b89..0f7f05077f 100644 --- a/spring-tx/src/main/java/org/springframework/jca/endpoint/AbstractMessageEndpointFactory.java +++ b/spring-tx/src/main/java/org/springframework/jca/endpoint/AbstractMessageEndpointFactory.java @@ -33,6 +33,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.lang.Nullable; import org.springframework.transaction.jta.SimpleTransactionFactory; import org.springframework.transaction.jta.TransactionFactory; +import org.springframework.util.Assert; /** * Abstract base implementation of the JCA 1.7 @@ -49,12 +50,15 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private TransactionFactory transactionFactory; + @Nullable private String transactionName; private int transactionTimeout = -1; + @Nullable private String beanName; @@ -201,10 +205,12 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF */ protected abstract class AbstractMessageEndpoint implements MessageEndpoint { + @Nullable private TransactionDelegate transactionDelegate; private boolean beforeDeliveryCalled = false; + @Nullable private ClassLoader previousContextClassLoader; /** @@ -228,6 +234,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF @Override public void beforeDelivery(@Nullable Method method) throws ResourceException { this.beforeDeliveryCalled = true; + Assert.state(this.transactionDelegate != null, "Not initialized"); try { this.transactionDelegate.beginTransaction(); } @@ -263,6 +270,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF * @param ex the exception thrown from the concrete endpoint */ protected final void onEndpointException(Throwable ex) { + Assert.state(this.transactionDelegate != null, "Not initialized"); this.transactionDelegate.setRollbackOnly(); } @@ -275,6 +283,7 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF */ @Override public void afterDelivery() throws ResourceException { + Assert.state(this.transactionDelegate != null, "Not initialized"); this.beforeDeliveryCalled = false; Thread.currentThread().setContextClassLoader(this.previousContextClassLoader); this.previousContextClassLoader = null; @@ -288,12 +297,14 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF @Override public void release() { - try { - this.transactionDelegate.setRollbackOnly(); - this.transactionDelegate.endTransaction(); - } - catch (Throwable ex) { - logger.error("Could not complete unfinished transaction on endpoint release", ex); + if (this.transactionDelegate != null) { + try { + this.transactionDelegate.setRollbackOnly(); + this.transactionDelegate.endTransaction(); + } + catch (Throwable ex) { + logger.error("Could not complete unfinished transaction on endpoint release", ex); + } } } } @@ -305,8 +316,10 @@ public abstract class AbstractMessageEndpointFactory implements MessageEndpointF */ private class TransactionDelegate { + @Nullable private final XAResource xaResource; + @Nullable private Transaction transaction; private boolean rollbackOnly; diff --git a/spring-tx/src/main/java/org/springframework/jca/support/LocalConnectionFactoryBean.java b/spring-tx/src/main/java/org/springframework/jca/support/LocalConnectionFactoryBean.java index d69faab355..70c1b13c3f 100644 --- a/spring-tx/src/main/java/org/springframework/jca/support/LocalConnectionFactoryBean.java +++ b/spring-tx/src/main/java/org/springframework/jca/support/LocalConnectionFactoryBean.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 javax.resource.spi.ManagedConnectionFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * {@link org.springframework.beans.factory.FactoryBean} that creates @@ -70,10 +71,13 @@ import org.springframework.beans.factory.InitializingBean; */ public class LocalConnectionFactoryBean implements FactoryBean, InitializingBean { + @Nullable private ManagedConnectionFactory managedConnectionFactory; + @Nullable private ConnectionManager connectionManager; + @Nullable private Object connectionFactory; diff --git a/spring-tx/src/main/java/org/springframework/jca/support/ResourceAdapterFactoryBean.java b/spring-tx/src/main/java/org/springframework/jca/support/ResourceAdapterFactoryBean.java index d4b7d3084e..23f511f3fe 100644 --- a/spring-tx/src/main/java/org/springframework/jca/support/ResourceAdapterFactoryBean.java +++ b/spring-tx/src/main/java/org/springframework/jca/support/ResourceAdapterFactoryBean.java @@ -26,6 +26,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * {@link org.springframework.beans.factory.FactoryBean} that bootstraps @@ -49,12 +50,16 @@ import org.springframework.beans.factory.InitializingBean; */ public class ResourceAdapterFactoryBean implements FactoryBean, InitializingBean, DisposableBean { + @Nullable private ResourceAdapter resourceAdapter; + @Nullable private BootstrapContext bootstrapContext; + @Nullable private WorkManager workManager; + @Nullable private XATerminator xaTerminator; @@ -145,7 +150,9 @@ public class ResourceAdapterFactoryBean implements FactoryBean, */ @Override public void destroy() { - this.resourceAdapter.stop(); + if (this.resourceAdapter != null) { + this.resourceAdapter.stop(); + } } } diff --git a/spring-tx/src/main/java/org/springframework/jca/support/SimpleBootstrapContext.java b/spring-tx/src/main/java/org/springframework/jca/support/SimpleBootstrapContext.java index 1ecfd9be86..39285bafb8 100644 --- a/spring-tx/src/main/java/org/springframework/jca/support/SimpleBootstrapContext.java +++ b/spring-tx/src/main/java/org/springframework/jca/support/SimpleBootstrapContext.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.jca.support; import java.util.Timer; - import javax.resource.spi.BootstrapContext; import javax.resource.spi.UnavailableException; import javax.resource.spi.XATerminator; @@ -26,6 +25,7 @@ import javax.resource.spi.work.WorkManager; import javax.transaction.TransactionSynchronizationRegistry; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Simple implementation of the JCA 1.7 {@link javax.resource.spi.BootstrapContext} @@ -41,10 +41,13 @@ import org.springframework.lang.Nullable; */ public class SimpleBootstrapContext implements BootstrapContext { + @Nullable private WorkManager workManager; + @Nullable private XATerminator xaTerminator; + @Nullable private TransactionSynchronizationRegistry transactionSynchronizationRegistry; @@ -87,13 +90,12 @@ public class SimpleBootstrapContext implements BootstrapContext { @Override public WorkManager getWorkManager() { - if (this.workManager == null) { - throw new IllegalStateException("No WorkManager available"); - } + Assert.state(this.workManager != null, "No WorkManager available"); return this.workManager; } @Override + @Nullable public XATerminator getXATerminator() { return this.xaTerminator; } @@ -109,6 +111,7 @@ public class SimpleBootstrapContext implements BootstrapContext { } @Override + @Nullable public TransactionSynchronizationRegistry getTransactionSynchronizationRegistry() { return this.transactionSynchronizationRegistry; } diff --git a/spring-tx/src/main/java/org/springframework/jca/work/SimpleTaskWorkManager.java b/spring-tx/src/main/java/org/springframework/jca/work/SimpleTaskWorkManager.java index cc12458230..62fddbbc09 100644 --- a/spring-tx/src/main/java/org/springframework/jca/work/SimpleTaskWorkManager.java +++ b/spring-tx/src/main/java/org/springframework/jca/work/SimpleTaskWorkManager.java @@ -63,8 +63,10 @@ import org.springframework.util.Assert; */ public class SimpleTaskWorkManager implements WorkManager { + @Nullable private TaskExecutor syncTaskExecutor = new SyncTaskExecutor(); + @Nullable private AsyncTaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor(); @@ -238,16 +240,11 @@ public class SimpleTaskWorkManager implements WorkManager { try { this.work.run(); } - catch (RuntimeException ex) { + catch (RuntimeException | Error ex) { this.workListener.workCompleted( new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(ex))); throw ex; } - catch (Error err) { - this.workListener.workCompleted( - new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException(err))); - throw err; - } this.workListener.workCompleted(new WorkEvent(this, WorkEvent.WORK_COMPLETED, this.work, null)); } diff --git a/spring-tx/src/main/java/org/springframework/jca/work/WorkManagerTaskExecutor.java b/spring-tx/src/main/java/org/springframework/jca/work/WorkManagerTaskExecutor.java index 5aafc72b54..cdc5800d2c 100644 --- a/spring-tx/src/main/java/org/springframework/jca/work/WorkManagerTaskExecutor.java +++ b/spring-tx/src/main/java/org/springframework/jca/work/WorkManagerTaskExecutor.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. @@ -70,16 +70,20 @@ import org.springframework.util.concurrent.ListenableFutureTask; public class WorkManagerTaskExecutor extends JndiLocatorSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, WorkManager, BootstrapContextAware, InitializingBean { + @Nullable private WorkManager workManager; + @Nullable private String workManagerName; private boolean blockUntilStarted = false; private boolean blockUntilCompleted = false; + @Nullable private WorkListener workListener; + @Nullable private TaskDecorator taskDecorator; @@ -198,6 +202,11 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport return new SimpleTaskWorkManager(); } + private WorkManager obtainWorkManager() { + Assert.state(this.workManager != null, "No WorkManager specified"); + return this.workManager; + } + //------------------------------------------------------------------------- // Implementation of the Spring SchedulingTaskExecutor interface @@ -210,31 +219,30 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @Override public void execute(Runnable task, long startTimeout) { - Assert.state(this.workManager != null, "No WorkManager specified"); Work work = new DelegatingWork(this.taskDecorator != null ? this.taskDecorator.decorate(task) : task); try { if (this.blockUntilCompleted) { if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) { - this.workManager.doWork(work, startTimeout, null, this.workListener); + obtainWorkManager().doWork(work, startTimeout, null, this.workListener); } else { - this.workManager.doWork(work); + obtainWorkManager().doWork(work); } } else if (this.blockUntilStarted) { if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) { - this.workManager.startWork(work, startTimeout, null, this.workListener); + obtainWorkManager().startWork(work, startTimeout, null, this.workListener); } else { - this.workManager.startWork(work); + obtainWorkManager().startWork(work); } } else { if (startTimeout != TIMEOUT_INDEFINITE || this.workListener != null) { - this.workManager.scheduleWork(work, startTimeout, null, this.workListener); + obtainWorkManager().scheduleWork(work, startTimeout, null, this.workListener); } else { - this.workManager.scheduleWork(work); + obtainWorkManager().scheduleWork(work); } } } @@ -294,38 +302,38 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @Override public void doWork(Work work) throws WorkException { - this.workManager.doWork(work); + obtainWorkManager().doWork(work); } @Override public void doWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener) throws WorkException { - this.workManager.doWork(work, delay, executionContext, workListener); + obtainWorkManager().doWork(work, delay, executionContext, workListener); } @Override public long startWork(Work work) throws WorkException { - return this.workManager.startWork(work); + return obtainWorkManager().startWork(work); } @Override public long startWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener) throws WorkException { - return this.workManager.startWork(work, delay, executionContext, workListener); + return obtainWorkManager().startWork(work, delay, executionContext, workListener); } @Override public void scheduleWork(Work work) throws WorkException { - this.workManager.scheduleWork(work); + obtainWorkManager().scheduleWork(work); } @Override public void scheduleWork(Work work, long delay, ExecutionContext executionContext, WorkListener workListener) throws WorkException { - this.workManager.scheduleWork(work, delay, executionContext, workListener); + obtainWorkManager().scheduleWork(work, delay, executionContext, workListener); } } diff --git a/spring-tx/src/main/java/org/springframework/transaction/TransactionSystemException.java b/spring-tx/src/main/java/org/springframework/transaction/TransactionSystemException.java index bd2ff4c3bc..e33071e6a1 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/TransactionSystemException.java +++ b/spring-tx/src/main/java/org/springframework/transaction/TransactionSystemException.java @@ -29,6 +29,7 @@ import org.springframework.util.Assert; @SuppressWarnings("serial") public class TransactionSystemException extends TransactionException { + @Nullable private Throwable applicationException; diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java index dd759298ff..548400d75a 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.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. @@ -26,6 +26,7 @@ import org.springframework.context.annotation.ImportAware; import org.springframework.context.annotation.Role; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.lang.Nullable; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.config.TransactionManagementConfigUtils; import org.springframework.transaction.event.TransactionalEventListenerFactory; @@ -43,11 +44,13 @@ import org.springframework.util.CollectionUtils; @Configuration public abstract class AbstractTransactionManagementConfiguration implements ImportAware { + @Nullable protected AnnotationAttributes enableTx; /** * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}. */ + @Nullable protected PlatformTransactionManager txManager; diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java index 616551c67b..5a5faaefc1 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.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. @@ -43,7 +43,9 @@ public class ProxyTransactionManagementConfiguration extends AbstractTransaction BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource()); advisor.setAdvice(transactionInterceptor()); - advisor.setOrder(this.enableTx.getNumber("order")); + if (this.enableTx != null) { + advisor.setOrder(this.enableTx.getNumber("order")); + } return advisor; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/config/JtaTransactionManagerFactoryBean.java b/spring-tx/src/main/java/org/springframework/transaction/config/JtaTransactionManagerFactoryBean.java index dd1e0779b4..4fe53cd782 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/config/JtaTransactionManagerFactoryBean.java +++ b/spring-tx/src/main/java/org/springframework/transaction/config/JtaTransactionManagerFactoryBean.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.transaction.config; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.util.ClassUtils; @@ -50,6 +51,7 @@ public class JtaTransactionManagerFactoryBean implements FactoryBean targetClass, Method method) { super(beanName, targetClass, method); - this.annotation = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class); - if (this.annotation == null) { + TransactionalEventListener ann = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class); + if (ann == null) { throw new IllegalStateException("No TransactionalEventListener annotation found on method: " + method); } + this.annotation = ann; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java index 753f6b25df..7f3be699c5 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java @@ -30,8 +30,10 @@ import org.springframework.transaction.support.DefaultTransactionDefinition; @SuppressWarnings("serial") public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute { + @Nullable private String qualifier; + @Nullable private String descriptor; diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java index d78ef28d94..252dab3984 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java @@ -50,8 +50,10 @@ public class MethodMapTransactionAttributeSource protected final Log logger = LogFactory.getLog(getClass()); /** Map from method name to attribute value */ + @Nullable private Map methodMap; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private boolean eagerlyInitialized = false; diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttribute.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttribute.java index e0784b9979..0445b599ae 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttribute.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/RuleBasedTransactionAttribute.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,6 +24,8 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.lang.Nullable; + /** * TransactionAttribute implementation that works out whether a given exception * should cause transaction rollback by applying a number of rollback rules, @@ -50,6 +52,7 @@ public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute i /** Static for optimal serializability */ private static final Log logger = LogFactory.getLog(RuleBasedTransactionAttribute.class); + @Nullable private List rollbackRules; @@ -78,7 +81,7 @@ public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute i */ public RuleBasedTransactionAttribute(RuleBasedTransactionAttribute other) { super(other); - this.rollbackRules = new ArrayList<>(other.rollbackRules); + this.rollbackRules = (other.rollbackRules != null ? new ArrayList<>(other.rollbackRules) : null); } /** diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java index 3bf1e39bf0..5036205d41 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java @@ -129,12 +129,16 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private String transactionManagerBeanName; + @Nullable private PlatformTransactionManager transactionManager; + @Nullable private TransactionAttributeSource transactionAttributeSource; + @Nullable private BeanFactory beanFactory; private final ConcurrentMap transactionManagerCache = @@ -151,6 +155,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init /** * Return the name of the default transaction manager bean. */ + @Nullable protected final String getTransactionManagerBeanName() { return this.transactionManagerBeanName; } @@ -236,6 +241,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init /** * Return the BeanFactory to use for retrieving PlatformTransactionManager beans. */ + @Nullable protected final BeanFactory getBeanFactory() { return this.beanFactory; } @@ -361,10 +367,10 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init String qualifier = txAttr.getQualifier(); if (StringUtils.hasText(qualifier)) { - return determineQualifiedTransactionManager(qualifier); + return determineQualifiedTransactionManager(this.beanFactory, qualifier); } else if (StringUtils.hasText(this.transactionManagerBeanName)) { - return determineQualifiedTransactionManager(this.transactionManagerBeanName); + return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName); } else { PlatformTransactionManager defaultTransactionManager = getTransactionManager(); @@ -380,11 +386,11 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init } } - private PlatformTransactionManager determineQualifiedTransactionManager(String qualifier) { + private PlatformTransactionManager determineQualifiedTransactionManager(BeanFactory beanFactory, String qualifier) { PlatformTransactionManager txManager = this.transactionManagerCache.get(qualifier); if (txManager == null) { txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType( - this.beanFactory, PlatformTransactionManager.class, qualifier); + beanFactory, PlatformTransactionManager.class, qualifier); this.transactionManagerCache.putIfAbsent(qualifier, txManager); } return txManager; @@ -505,7 +511,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init * @param txInfo information about the current transaction */ protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) { - if (txInfo != null && txInfo.hasTransaction()) { + if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]"); } @@ -520,7 +526,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init * @param ex throwable encountered */ protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { - if (txInfo != null && txInfo.hasTransaction()) { + if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); @@ -584,14 +590,18 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init */ protected final class TransactionInfo { + @Nullable private final PlatformTransactionManager transactionManager; + @Nullable private final TransactionAttribute transactionAttribute; private final String joinpointIdentification; + @Nullable private TransactionStatus transactionStatus; + @Nullable private TransactionInfo oldTransactionInfo; public TransactionInfo(@Nullable PlatformTransactionManager transactionManager, @@ -624,6 +634,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init this.transactionStatus = status; } + @Nullable public TransactionStatus getTransactionStatus() { return this.transactionStatus; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttribute.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttribute.java index debf7a9523..2b0ecdc6c2 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttribute.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttribute.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.transaction.interceptor; +import org.springframework.lang.Nullable; import org.springframework.transaction.TransactionDefinition; /** @@ -36,6 +37,7 @@ public interface TransactionAttribute extends TransactionDefinition { *

This may be used for choosing a corresponding transaction manager * to process this specific transaction. */ + @Nullable String getQualifier(); /** diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.java index 3795ec8234..bf91b50c17 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.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,8 @@ import org.aopalliance.aop.Advice; import org.springframework.aop.ClassFilter; import org.springframework.aop.Pointcut; import org.springframework.aop.support.AbstractPointcutAdvisor; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Advisor driven by a {@link TransactionAttributeSource}, used to include @@ -38,6 +40,7 @@ import org.springframework.aop.support.AbstractPointcutAdvisor; @SuppressWarnings("serial") public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor { + @Nullable private TransactionInterceptor transactionInterceptor; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @@ -81,6 +84,7 @@ public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor { @Override public Advice getAdvice() { + Assert.state(this.transactionInterceptor != null, "No TransactionInterceptor set"); return this.transactionInterceptor; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.java index 7d9b67f01d..91558e9258 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.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. @@ -26,6 +26,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.lang.Nullable; import org.springframework.transaction.PlatformTransactionManager; /** @@ -117,6 +118,7 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); + @Nullable private Pointcut pointcut; diff --git a/spring-tx/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java b/spring-tx/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java index daeef1ba07..32fa09c8ba 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java +++ b/spring-tx/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java @@ -149,8 +149,10 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager private transient JndiTemplate jndiTemplate = new JndiTemplate(); + @Nullable private transient UserTransaction userTransaction; + @Nullable private String userTransactionName; private boolean autodetectUserTransaction = true; @@ -159,14 +161,18 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager private boolean userTransactionObtainedFromJndi = false; + @Nullable private transient TransactionManager transactionManager; + @Nullable private String transactionManagerName; private boolean autodetectTransactionManager = true; + @Nullable private transient TransactionSynchronizationRegistry transactionSynchronizationRegistry; + @Nullable private String transactionSynchronizationRegistryName; private boolean autodetectTransactionSynchronizationRegistry = true; @@ -743,8 +749,8 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager * @throws TransactionSystemException in case of errors */ @Nullable - protected TransactionSynchronizationRegistry findTransactionSynchronizationRegistry(UserTransaction ut, TransactionManager tm) - throws TransactionSystemException { + protected TransactionSynchronizationRegistry findTransactionSynchronizationRegistry( + @Nullable UserTransaction ut, @Nullable TransactionManager tm) throws TransactionSystemException { if (this.userTransactionObtainedFromJndi) { // UserTransaction has already been obtained from JNDI, so the diff --git a/spring-tx/src/main/java/org/springframework/transaction/jta/SpringJtaSynchronizationAdapter.java b/spring-tx/src/main/java/org/springframework/transaction/jta/SpringJtaSynchronizationAdapter.java index 6f3d59d18d..b490bd015b 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/jta/SpringJtaSynchronizationAdapter.java +++ b/spring-tx/src/main/java/org/springframework/transaction/jta/SpringJtaSynchronizationAdapter.java @@ -49,6 +49,7 @@ public class SpringJtaSynchronizationAdapter implements Synchronization { private final TransactionSynchronization springSynchronization; + @Nullable private UserTransaction jtaTransaction; private boolean beforeCompletionCalled = false; diff --git a/spring-tx/src/main/java/org/springframework/transaction/jta/WebLogicJtaTransactionManager.java b/spring-tx/src/main/java/org/springframework/transaction/jta/WebLogicJtaTransactionManager.java index 94514a0702..ef9ad33c4a 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/jta/WebLogicJtaTransactionManager.java +++ b/spring-tx/src/main/java/org/springframework/transaction/jta/WebLogicJtaTransactionManager.java @@ -88,16 +88,21 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { private boolean weblogicUserTransactionAvailable; + @Nullable private Method beginWithNameMethod; + @Nullable private Method beginWithNameAndTimeoutMethod; private boolean weblogicTransactionManagerAvailable; + @Nullable private Method forceResumeMethod; + @Nullable private Method setPropertyMethod; + @Nullable private Object transactionHelper; @@ -109,10 +114,10 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { @Override protected UserTransaction retrieveUserTransaction() throws TransactionSystemException { - loadWebLogicTransactionHelper(); + Object helper = loadWebLogicTransactionHelper(); try { logger.debug("Retrieving JTA UserTransaction from WebLogic TransactionHelper"); - Method getUserTransactionMethod = this.transactionHelper.getClass().getMethod("getUserTransaction"); + Method getUserTransactionMethod = helper.getClass().getMethod("getUserTransaction"); return (UserTransaction) getUserTransactionMethod.invoke(this.transactionHelper); } catch (InvocationTargetException ex) { @@ -127,10 +132,10 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { @Override protected TransactionManager retrieveTransactionManager() throws TransactionSystemException { - loadWebLogicTransactionHelper(); + Object helper = loadWebLogicTransactionHelper(); try { logger.debug("Retrieving JTA TransactionManager from WebLogic TransactionHelper"); - Method getTransactionManagerMethod = this.transactionHelper.getClass().getMethod("getTransactionManager"); + Method getTransactionManagerMethod = helper.getClass().getMethod("getTransactionManager"); return (TransactionManager) getTransactionManagerMethod.invoke(this.transactionHelper); } catch (InvocationTargetException ex) { @@ -143,12 +148,14 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { } } - private void loadWebLogicTransactionHelper() throws TransactionSystemException { - if (this.transactionHelper == null) { + private Object loadWebLogicTransactionHelper() throws TransactionSystemException { + Object helper = this.transactionHelper; + if (helper == null) { try { Class transactionHelperClass = getClass().getClassLoader().loadClass(TRANSACTION_HELPER_CLASS_NAME); Method getTransactionHelperMethod = transactionHelperClass.getMethod("getTransactionHelper"); - this.transactionHelper = getTransactionHelperMethod.invoke(null); + helper = getTransactionHelperMethod.invoke(null); + this.transactionHelper = helper; logger.debug("WebLogic TransactionHelper found"); } catch (InvocationTargetException ex) { @@ -161,6 +168,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { ex); } } + return helper; } private void loadWebLogicTransactionClasses() throws TransactionSystemException { @@ -220,6 +228,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut; wut.begin(definition.getName(), timeout); */ + Assert.state(this.beginWithNameAndTimeoutMethod != null, "WebLogic JTA API not initialized"); this.beginWithNameAndTimeoutMethod.invoke(txObject.getUserTransaction(), definition.getName(), timeout); } else { @@ -227,6 +236,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { weblogic.transaction.UserTransaction wut = (weblogic.transaction.UserTransaction) ut; wut.begin(definition.getName()); */ + Assert.state(this.beginWithNameMethod != null, "WebLogic JTA API not initialized"); this.beginWithNameMethod.invoke(txObject.getUserTransaction(), definition.getName()); } } @@ -256,6 +266,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { weblogic.transaction.Transaction wtx = (weblogic.transaction.Transaction) tx; wtx.setProperty(ISOLATION_LEVEL_KEY, isolationLevel); */ + Assert.state(this.setPropertyMethod != null, "WebLogic JTA API not initialized"); this.setPropertyMethod.invoke(tx, ISOLATION_LEVEL_KEY, isolationLevel); } catch (InvocationTargetException ex) { @@ -274,7 +285,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { } @Override - protected void doJtaResume(JtaTransactionObject txObject, Object suspendedTransaction) + protected void doJtaResume(@Nullable JtaTransactionObject txObject, Object suspendedTransaction) throws InvalidTransactionException, SystemException { try { @@ -295,6 +306,7 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { wtm.forceResume(suspendedTransaction); */ try { + Assert.state(this.forceResumeMethod != null, "WebLogic JTA API not initialized"); this.forceResumeMethod.invoke(getTransactionManager(), suspendedTransaction); } catch (InvocationTargetException ex2) { @@ -313,9 +325,11 @@ public class WebLogicJtaTransactionManager extends JtaTransactionManager { if (this.weblogicUserTransactionAvailable && name != null) { try { if (timeout >= 0) { + Assert.state(this.beginWithNameAndTimeoutMethod != null, "WebLogic JTA API not initialized"); this.beginWithNameAndTimeoutMethod.invoke(getUserTransaction(), name, timeout); } else { + Assert.state(this.beginWithNameMethod != null, "WebLogic JTA API not initialized"); this.beginWithNameMethod.invoke(getUserTransaction(), name); } } diff --git a/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java b/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java index 905f4bd2e0..9e334ae79b 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java +++ b/spring-tx/src/main/java/org/springframework/transaction/jta/WebSphereUowTransactionManager.java @@ -41,6 +41,7 @@ import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationUtils; +import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; /** @@ -96,8 +97,10 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager public static final String DEFAULT_UOW_MANAGER_NAME = "java:comp/websphere/UOWManager"; + @Nullable private UOWManager uowManager; + @Nullable private String uowManagerName; @@ -194,6 +197,12 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager } } + private UOWManager obtainUOWManager() { + Assert.state(this.uowManager != null, "No UOWManager set"); + return this.uowManager; + } + + /** * Registers the synchronizations as interposed JTA Synchronization on the UOWManager. */ @@ -201,7 +210,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager protected void doRegisterAfterCompletionWithJtaTransaction( JtaTransactionObject txObject, List synchronizations) { - this.uowManager.registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations)); + obtainUOWManager().registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations)); } /** @@ -231,9 +240,11 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout()); } + + UOWManager uowManager = obtainUOWManager(); int pb = definition.getPropagationBehavior(); - boolean existingTx = (this.uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE && - this.uowManager.getUOWType() != UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION); + boolean existingTx = (uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE && + uowManager.getUOWType() != UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION); int uowType = UOWSynchronizationRegistry.UOW_TYPE_GLOBAL_TRANSACTION; boolean joinTx = false; @@ -283,14 +294,14 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null); try { if (definition.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) { - this.uowManager.setUOWTimeout(uowType, definition.getTimeout()); + uowManager.setUOWTimeout(uowType, definition.getTimeout()); } if (debug) { logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx); } UOWActionAdapter action = new UOWActionAdapter<>( definition, callback, (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION), !joinTx, newSynch, debug); - this.uowManager.runUnderUOW(uowType, joinTx, action); + uowManager.runUnderUOW(uowType, joinTx, action); if (debug) { logger.debug("Returned from WebSphere UOW action: type=" + uowType + ", join=" + joinTx); } @@ -327,12 +338,15 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager private boolean debug; + @Nullable private T result; + @Nullable private Throwable exception; public UOWActionAdapter(TransactionDefinition definition, TransactionCallback callback, boolean actualTransaction, boolean newTransaction, boolean newSynchronization, boolean debug) { + this.definition = definition; this.callback = callback; this.actualTransaction = actualTransaction; @@ -343,6 +357,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager @Override public void run() { + UOWManager uowManager = obtainUOWManager(); DefaultTransactionStatus status = prepareTransactionStatus( this.definition, (this.actualTransaction ? this : null), this.newTransaction, this.newSynchronization, this.debug, null); @@ -372,6 +387,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager } } + @Nullable public T getResult() { if (this.exception != null) { ReflectionUtils.rethrowRuntimeException(this.exception); @@ -381,7 +397,7 @@ public class WebSphereUowTransactionManager extends JtaTransactionManager @Override public boolean isRollbackOnly() { - return uowManager.getRollbackOnly(); + return obtainUOWManager().getRollbackOnly(); } @Override diff --git a/spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java b/spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java index e20e6292b9..b9cbfe6d87 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java +++ b/spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java @@ -1271,14 +1271,18 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran */ protected static class SuspendedResourcesHolder { + @Nullable private final Object suspendedResources; + @Nullable private List suspendedSynchronizations; + @Nullable private String name; private boolean readOnly; + @Nullable private Integer isolationLevel; private boolean wasActive; diff --git a/spring-tx/src/main/java/org/springframework/transaction/support/AbstractTransactionStatus.java b/spring-tx/src/main/java/org/springframework/transaction/support/AbstractTransactionStatus.java index f67f99c378..038c15fd6c 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/support/AbstractTransactionStatus.java +++ b/spring-tx/src/main/java/org/springframework/transaction/support/AbstractTransactionStatus.java @@ -50,6 +50,7 @@ public abstract class AbstractTransactionStatus implements TransactionStatus { private boolean completed = false; + @Nullable private Object savepoint; diff --git a/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionDefinition.java b/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionDefinition.java index edd0b76e59..56bd8f8aa6 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionDefinition.java +++ b/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionDefinition.java @@ -19,6 +19,7 @@ package org.springframework.transaction.support; import java.io.Serializable; import org.springframework.core.Constants; +import org.springframework.lang.Nullable; import org.springframework.transaction.TransactionDefinition; /** @@ -59,6 +60,7 @@ public class DefaultTransactionDefinition implements TransactionDefinition, Seri private boolean readOnly = false; + @Nullable private String name; diff --git a/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionStatus.java b/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionStatus.java index 968d5e19e8..cfa9443804 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionStatus.java +++ b/spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionStatus.java @@ -50,6 +50,7 @@ import org.springframework.util.Assert; */ public class DefaultTransactionStatus extends AbstractTransactionStatus { + @Nullable private final Object transaction; private final boolean newTransaction; @@ -60,6 +61,7 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus { private final boolean debug; + @Nullable private final Object suspendedResources; diff --git a/spring-tx/src/main/java/org/springframework/transaction/support/ResourceHolderSupport.java b/spring-tx/src/main/java/org/springframework/transaction/support/ResourceHolderSupport.java index bf9ecb517f..dadabb1640 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/support/ResourceHolderSupport.java +++ b/spring-tx/src/main/java/org/springframework/transaction/support/ResourceHolderSupport.java @@ -18,6 +18,7 @@ package org.springframework.transaction.support; import java.util.Date; +import org.springframework.lang.Nullable; import org.springframework.transaction.TransactionTimedOutException; /** @@ -38,6 +39,7 @@ public abstract class ResourceHolderSupport implements ResourceHolder { private boolean rollbackOnly = false; + @Nullable private Date deadline; private int referenceCount = 0; @@ -111,6 +113,7 @@ public abstract class ResourceHolderSupport implements ResourceHolder { * Return the expiration deadline of this object. * @return the deadline as Date object */ + @Nullable public Date getDeadline() { return this.deadline; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/support/TransactionTemplate.java b/spring-tx/src/main/java/org/springframework/transaction/support/TransactionTemplate.java index b2fd8ce019..2d3d650d17 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/support/TransactionTemplate.java +++ b/spring-tx/src/main/java/org/springframework/transaction/support/TransactionTemplate.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,11 +22,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionSystemException; +import org.springframework.util.Assert; /** * Template class that simplifies programmatic transaction demarcation and @@ -66,6 +68,7 @@ public class TransactionTemplate extends DefaultTransactionDefinition /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private PlatformTransactionManager transactionManager; @@ -109,6 +112,7 @@ public class TransactionTemplate extends DefaultTransactionDefinition /** * Return the transaction management strategy to be used. */ + @Nullable public PlatformTransactionManager getTransactionManager() { return this.transactionManager; } @@ -123,6 +127,8 @@ public class TransactionTemplate extends DefaultTransactionDefinition @Override public T execute(TransactionCallback action) throws TransactionException { + Assert.state(this.transactionManager != null, "No PlatformTransactionManager set"); + if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } @@ -132,16 +138,11 @@ public class TransactionTemplate extends DefaultTransactionDefinition try { result = action.doInTransaction(status); } - catch (RuntimeException ex) { + catch (RuntimeException | Error ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } - catch (Error err) { - // Transactional code threw error -> rollback - rollbackOnException(status, err); - throw err; - } catch (Throwable ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); @@ -159,6 +160,8 @@ public class TransactionTemplate extends DefaultTransactionDefinition * @throws TransactionException in case of a rollback error */ private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException { + Assert.state(this.transactionManager != null, "No PlatformTransactionManager set"); + logger.debug("Initiating transaction rollback on application exception", ex); try { this.transactionManager.rollback(status); diff --git a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java index a9f8774b18..11c381ba68 100644 --- a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java +++ b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java @@ -40,28 +40,38 @@ import static java.time.format.DateTimeFormatter.*; */ public class ContentDisposition { + @Nullable private final String type; + @Nullable private final String name; + @Nullable private final String filename; + @Nullable private final Charset charset; + @Nullable private final Long size; + @Nullable private final ZonedDateTime creationDate; + @Nullable private final ZonedDateTime modificationDate; + @Nullable private final ZonedDateTime readDate; /** * Private constructor. See static factory methods in this class. */ - private ContentDisposition(@Nullable String type, @Nullable String name, @Nullable String filename, @Nullable Charset charset, @Nullable Long size, - @Nullable ZonedDateTime creationDate, @Nullable ZonedDateTime modificationDate, @Nullable ZonedDateTime readDate) { + private ContentDisposition(@Nullable String type, @Nullable String name, @Nullable String filename, + @Nullable Charset charset, @Nullable Long size, @Nullable ZonedDateTime creationDate, + @Nullable ZonedDateTime modificationDate, @Nullable ZonedDateTime readDate) { + this.type = type; this.name = name; this.filename = filename; @@ -435,28 +445,34 @@ public class ContentDisposition { * Build the content disposition */ ContentDisposition build(); - } + private static class BuilderImpl implements Builder { private String type; + @Nullable private String name; + @Nullable private String filename; + @Nullable private Charset charset; + @Nullable private Long size; + @Nullable private ZonedDateTime creationDate; + @Nullable private ZonedDateTime modificationDate; + @Nullable private ZonedDateTime readDate; - public BuilderImpl(String type) { Assert.hasText(type, "'type' must not be not empty"); this.type = type; diff --git a/spring-web/src/main/java/org/springframework/http/HttpEntity.java b/spring-web/src/main/java/org/springframework/http/HttpEntity.java index b88f74ae85..38c1d3fddd 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpEntity.java +++ b/spring-web/src/main/java/org/springframework/http/HttpEntity.java @@ -64,6 +64,7 @@ public class HttpEntity { private final HttpHeaders headers; + @Nullable private final T body; @@ -151,13 +152,9 @@ public class HttpEntity { StringBuilder builder = new StringBuilder("<"); if (this.body != null) { builder.append(this.body); - if (this.headers != null) { - builder.append(','); - } - } - if (this.headers != null) { - builder.append(this.headers); + builder.append(','); } + builder.append(this.headers); builder.append('>'); return builder.toString(); } diff --git a/spring-web/src/main/java/org/springframework/http/HttpRange.java b/spring-web/src/main/java/org/springframework/http/HttpRange.java index 736fe9c51b..3bd2485f3c 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpRange.java +++ b/spring-web/src/main/java/org/springframework/http/HttpRange.java @@ -212,6 +212,7 @@ public abstract class HttpRange { private final long firstPos; + @Nullable private final Long lastPos; public ByteRange(long firstPos, @Nullable Long lastPos) { diff --git a/spring-web/src/main/java/org/springframework/http/RequestEntity.java b/spring-web/src/main/java/org/springframework/http/RequestEntity.java index bbe787c485..8fcd40a54c 100644 --- a/spring-web/src/main/java/org/springframework/http/RequestEntity.java +++ b/spring-web/src/main/java/org/springframework/http/RequestEntity.java @@ -62,10 +62,12 @@ import org.springframework.util.ObjectUtils; */ public class RequestEntity extends HttpEntity { + @Nullable private final HttpMethod method; private final URI url; + @Nullable private final Type type; diff --git a/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingAsyncClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingAsyncClientHttpRequest.java index c5ec370435..e1609737f5 100644 --- a/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingAsyncClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingAsyncClientHttpRequest.java @@ -49,7 +49,7 @@ abstract class AbstractBufferingAsyncClientHttpRequest extends AbstractAsyncClie headers.setContentLength(bytes.length); } ListenableFuture result = executeInternal(headers, bytes); - this.bufferedOutput = null; + this.bufferedOutput = new ByteArrayOutputStream(0); return result; } diff --git a/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingClientHttpRequest.java index d468b5877b..60ddb0fa01 100644 --- a/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/AbstractBufferingClientHttpRequest.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. @@ -46,7 +46,7 @@ abstract class AbstractBufferingClientHttpRequest extends AbstractClientHttpRequ headers.setContentLength(bytes.length); } ClientHttpResponse result = executeInternal(headers, bytes); - this.bufferedOutput = null; + this.bufferedOutput = new ByteArrayOutputStream(0); return result; } diff --git a/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java b/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java index 297218281a..6ec3e7c712 100644 --- a/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java +++ b/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.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. @@ -22,6 +22,7 @@ import java.io.InputStream; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; import org.springframework.util.StreamUtils; /** @@ -35,6 +36,7 @@ final class BufferingClientHttpResponseWrapper implements ClientHttpResponse { private final ClientHttpResponse response; + @Nullable private byte[] body; diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java index ea2baaa4fd..9ab94ff514 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java @@ -33,6 +33,7 @@ import org.apache.http.protocol.HttpContext; import org.springframework.beans.factory.InitializingBean; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -50,6 +51,7 @@ import org.springframework.util.Assert; public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory implements AsyncClientHttpRequestFactory, InitializingBean { + @Nullable private HttpAsyncClient asyncClient; @@ -126,6 +128,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC * @since 4.3.10 * @see #getHttpClient() */ + @Nullable public HttpAsyncClient getAsyncClient() { return this.asyncClient; } @@ -158,19 +161,21 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC startAsyncClient(); } - private void startAsyncClient() { - HttpAsyncClient asyncClient = getAsyncClient(); - if (asyncClient instanceof CloseableHttpAsyncClient) { - CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) asyncClient; + private HttpAsyncClient startAsyncClient() { + HttpAsyncClient client = getAsyncClient(); + Assert.state(client != null, "No HttpAsyncClient set"); + if (client instanceof CloseableHttpAsyncClient) { + CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) client; if (!closeableAsyncClient.isRunning()) { closeableAsyncClient.start(); } } + return client; } @Override public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException { - startAsyncClient(); + HttpAsyncClient client = startAsyncClient(); HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); postProcessHttpRequest(httpRequest); @@ -187,14 +192,14 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC config = ((Configurable) httpRequest).getConfig(); } if (config == null) { - config = createRequestConfig(getAsyncClient()); + config = createRequestConfig(client); } if (config != null) { context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); } } - return new HttpComponentsAsyncClientHttpRequest(getAsyncClient(), httpRequest, context); + return new HttpComponentsAsyncClientHttpRequest(client, httpRequest, context); } @Override diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpResponse.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpResponse.java index 78e4646a0c..6f3c2dd072 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpResponse.java @@ -24,6 +24,7 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.StreamUtils; /** @@ -43,6 +44,7 @@ final class HttpComponentsAsyncClientHttpResponse extends AbstractClientHttpResp private final HttpResponse httpResponse; + @Nullable private HttpHeaders headers; diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java index 9eea0f02a5..a387a625bc 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java @@ -59,8 +59,10 @@ import org.springframework.util.Assert; */ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean { + @Nullable private HttpClient httpClient; + @Nullable private RequestConfig requestConfig; private boolean bufferRequestBody = true; @@ -97,6 +99,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest * Return the {@code HttpClient} used for * {@linkplain #createRequest(URI, HttpMethod) synchronous execution}. */ + @Nullable public HttpClient getHttpClient() { return this.httpClient; } @@ -152,6 +155,9 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest @Override public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { + HttpClient client = getHttpClient(); + Assert.state(client != null, "No HttpClient set"); + HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); postProcessHttpRequest(httpRequest); HttpContext context = createHttpContext(httpMethod, uri); @@ -167,7 +173,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest config = ((Configurable) httpRequest).getConfig(); } if (config == null) { - config = createRequestConfig(getHttpClient()); + config = createRequestConfig(client); } if (config != null) { context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); @@ -175,10 +181,10 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest } if (this.bufferRequestBody) { - return new HttpComponentsClientHttpRequest(getHttpClient(), httpRequest, context); + return new HttpComponentsClientHttpRequest(client, httpRequest, context); } else { - return new HttpComponentsStreamingClientHttpRequest(getHttpClient(), httpRequest, context); + return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context); } } diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpResponse.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpResponse.java index 3798a97d81..edfa670bf8 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpResponse.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. @@ -26,6 +26,7 @@ import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.StreamUtils; /** @@ -43,6 +44,7 @@ final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse private final HttpResponse httpResponse; + @Nullable private HttpHeaders headers; diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsStreamingClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsStreamingClientHttpRequest.java index 76ea968c5e..efc6dae9ce 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsStreamingClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsStreamingClientHttpRequest.java @@ -54,6 +54,7 @@ final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpR private final HttpContext httpContext; + @Nullable private Body body; @@ -89,9 +90,9 @@ final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpR protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { HttpComponentsClientHttpRequest.addHeaders(this.httpRequest, headers); - if (this.httpRequest instanceof HttpEntityEnclosingRequest && body != null) { + if (this.httpRequest instanceof HttpEntityEnclosingRequest && this.body != null) { HttpEntityEnclosingRequest entityEnclosingRequest = (HttpEntityEnclosingRequest) this.httpRequest; - HttpEntity requestEntity = new StreamingHttpEntity(getHeaders(), body); + HttpEntity requestEntity = new StreamingHttpEntity(getHeaders(), this.body); entityEnclosingRequest.setEntity(requestEntity); } diff --git a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java index 1850912547..399d5b8664 100644 --- a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpRequestFactory.java @@ -39,6 +39,7 @@ import io.netty.handler.timeout.ReadTimeoutHandler; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -75,12 +76,14 @@ public class Netty4ClientHttpRequestFactory implements ClientHttpRequestFactory, private int maxResponseSize = DEFAULT_MAX_RESPONSE_SIZE; + @Nullable private SslContext sslContext; private int connectTimeout = -1; private int readTimeout = -1; + @Nullable private volatile Bootstrap bootstrap; @@ -183,10 +186,12 @@ public class Netty4ClientHttpRequestFactory implements ClientHttpRequestFactory, return buildBootstrap(uri, true); } else { - if (this.bootstrap == null) { - this.bootstrap = buildBootstrap(uri, false); + Bootstrap bootstrap = this.bootstrap; + if (bootstrap == null) { + bootstrap = buildBootstrap(uri, false); + this.bootstrap = bootstrap; } - return this.bootstrap; + return bootstrap; } } diff --git a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpResponse.java b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpResponse.java index 8a795ccb7b..6556c47c3a 100644 --- a/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/client/Netty4ClientHttpResponse.java @@ -25,6 +25,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpResponse; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -43,6 +44,7 @@ class Netty4ClientHttpResponse extends AbstractClientHttpResponse { private final ByteBufInputStream body; + @Nullable private volatile HttpHeaders headers; @@ -70,14 +72,15 @@ class Netty4ClientHttpResponse extends AbstractClientHttpResponse { @Override public HttpHeaders getHeaders() { - if (this.headers == null) { - HttpHeaders headers = new HttpHeaders(); + HttpHeaders headers = this.headers; + if (headers == null) { + headers = new HttpHeaders(); for (Map.Entry entry : this.nettyResponse.headers()) { headers.add(entry.getKey(), entry.getValue()); } this.headers = headers; } - return this.headers; + return headers; } @Override diff --git a/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpResponse.java b/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpResponse.java index e00478fbe8..8b3774a8b7 100644 --- a/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/client/OkHttp3ClientHttpResponse.java @@ -23,6 +23,7 @@ import okhttp3.Response; import okhttp3.ResponseBody; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StreamUtils; @@ -38,7 +39,8 @@ class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse { private final Response response; - private HttpHeaders headers; + @Nullable + private volatile HttpHeaders headers; public OkHttp3ClientHttpResponse(Response response) { @@ -65,8 +67,9 @@ class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse { @Override public HttpHeaders getHeaders() { - if (this.headers == null) { - HttpHeaders headers = new HttpHeaders(); + HttpHeaders headers = this.headers; + if (headers == null) { + headers = new HttpHeaders(); for (String headerName : this.response.headers().names()) { for (String headerValue : this.response.headers(headerName)) { headers.add(headerName, headerValue); @@ -74,7 +77,7 @@ class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse { } this.headers = headers; } - return this.headers; + return headers; } @Override diff --git a/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpRequestFactory.java index ab821d58f9..f1131d98ea 100644 --- a/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpRequestFactory.java @@ -43,6 +43,7 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, private static final int DEFAULT_CHUNK_SIZE = 4096; + @Nullable private Proxy proxy; private boolean bufferRequestBody = true; @@ -55,6 +56,7 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, private boolean outputStreaming = true; + @Nullable private AsyncListenableTaskExecutor taskExecutor; diff --git a/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpResponse.java b/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpResponse.java index 28093d1b8b..caa7a38f10 100644 --- a/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpResponse.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. @@ -21,6 +21,7 @@ import java.io.InputStream; import java.net.HttpURLConnection; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; @@ -37,8 +38,10 @@ final class SimpleClientHttpResponse extends AbstractClientHttpResponse { private final HttpURLConnection connection; + @Nullable private HttpHeaders headers; + @Nullable private InputStream responseStream; diff --git a/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingAsyncClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingAsyncClientHttpRequest.java index cfb4338666..daa63d6033 100644 --- a/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingAsyncClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingAsyncClientHttpRequest.java @@ -25,6 +25,7 @@ import java.util.concurrent.Callable; import org.springframework.core.task.AsyncListenableTaskExecutor; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.StreamUtils; import org.springframework.util.concurrent.ListenableFuture; @@ -45,6 +46,7 @@ final class SimpleStreamingAsyncClientHttpRequest extends AbstractAsyncClientHtt private final int chunkSize; + @Nullable private OutputStream body; private final boolean outputStreaming; diff --git a/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingClientHttpRequest.java index 47acd49a25..fd0a1d0ddc 100644 --- a/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/SimpleStreamingClientHttpRequest.java @@ -24,6 +24,7 @@ import java.net.URISyntaxException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; import org.springframework.util.StreamUtils; /** @@ -40,6 +41,7 @@ final class SimpleStreamingClientHttpRequest extends AbstractClientHttpRequest { private final int chunkSize; + @Nullable private OutputStream body; private final boolean outputStreaming; diff --git a/spring-web/src/main/java/org/springframework/http/codec/AbstractCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/AbstractCodecConfigurer.java index 8776508c59..ee52ca2e00 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/AbstractCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/AbstractCodecConfigurer.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.http.codec; import java.util.ArrayList; @@ -35,10 +36,10 @@ import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.xml.Jaxb2XmlDecoder; import org.springframework.http.codec.xml.Jaxb2XmlEncoder; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; - /** * Default implementation of {@link CodecConfigurer}. * @@ -63,7 +64,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { protected AbstractCodecConfigurer(AbstractDefaultCodecs defaultCodecs) { - Assert.notNull(defaultCodecs, "'defaultCodecs' is required."); + Assert.notNull(defaultCodecs, "'defaultCodecs' is required"); this.defaultCodecs = defaultCodecs; this.defaultCodecs.setCustomCodecs(this.customCodecs); } @@ -117,13 +118,15 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { private boolean registerDefaults = true; + @Nullable private Jackson2JsonDecoder jackson2Decoder; + @Nullable private Jackson2JsonEncoder jackson2Encoder; + @Nullable private DefaultCustomCodecs customCodecs; - public void setRegisterDefaults(boolean registerDefaults) { this.registerDefaults = registerDefaults; } @@ -139,6 +142,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { this.customCodecs = customCodecs; } + @Nullable public DefaultCustomCodecs getCustomCodecs() { return this.customCodecs; } @@ -149,7 +153,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { } protected Jackson2JsonDecoder jackson2Decoder() { - return this.jackson2Decoder != null ? this.jackson2Decoder : new Jackson2JsonDecoder(); + return (this.jackson2Decoder != null ? this.jackson2Decoder : new Jackson2JsonDecoder()); } @Override @@ -158,7 +162,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { } protected Jackson2JsonEncoder jackson2Encoder() { - return this.jackson2Encoder != null ? this.jackson2Encoder : new Jackson2JsonEncoder(); + return (this.jackson2Encoder != null ? this.jackson2Encoder : new Jackson2JsonEncoder()); } // Readers... @@ -244,11 +248,12 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { protected static class DefaultCustomCodecs implements CustomCodecs { private final List> typedReaders = new ArrayList<>(); + private final List> typedWriters = new ArrayList<>(); private final List> objectReaders = new ArrayList<>(); - private final List> objectWriters = new ArrayList<>(); + private final List> objectWriters = new ArrayList<>(); @Override public void decoder(Decoder decoder) { @@ -272,7 +277,6 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { (canWriteObject ? this.objectWriters : this.typedWriters).add(writer); } - public List> getTypedReaders() { return this.typedReaders; } diff --git a/spring-web/src/main/java/org/springframework/http/codec/DefaultClientCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/DefaultClientCodecConfigurer.java index 2ae42f4ad4..b08a1f4c69 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/DefaultClientCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/DefaultClientCodecConfigurer.java @@ -23,6 +23,7 @@ import java.util.List; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; +import org.springframework.lang.Nullable; /** * Default implementation of {@link ClientCodecConfigurer}. @@ -32,26 +33,24 @@ import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; */ class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements ClientCodecConfigurer { - public DefaultClientCodecConfigurer() { super(new ClientDefaultCodecsImpl()); } - @Override public ClientDefaultCodecs defaultCodecs() { return (ClientDefaultCodecs) super.defaultCodecs(); } - private static class ClientDefaultCodecsImpl extends AbstractDefaultCodecs - implements ClientDefaultCodecs { + private static class ClientDefaultCodecsImpl extends AbstractDefaultCodecs implements ClientDefaultCodecs { + @Nullable private DefaultMultipartCodecs multipartCodecs; + @Nullable private Decoder sseDecoder; - @Override public MultipartCodecs multipartCodecs() { if (this.multipartCodecs == null) { @@ -65,7 +64,6 @@ class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements Cl this.sseDecoder = decoder; } - @Override protected boolean splitTextOnNewLine() { return false; @@ -105,22 +103,27 @@ class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements Cl partWriters = this.multipartCodecs.getWriters(); } else { + DefaultCustomCodecs customCodecs = getCustomCodecs(); partWriters = new ArrayList<>(); partWriters.addAll(super.getTypedWriters()); - partWriters.addAll(getCustomCodecs().getTypedWriters()); + if (customCodecs != null) { + partWriters.addAll(customCodecs.getTypedWriters()); + } partWriters.addAll(super.getObjectWriters()); - partWriters.addAll(getCustomCodecs().getObjectWriters()); + if (customCodecs != null) { + partWriters.addAll(customCodecs.getObjectWriters()); + } partWriters.addAll(super.getCatchAllWriters()); } return new MultipartHttpMessageWriter(partWriters); } } + private static class DefaultMultipartCodecs implements MultipartCodecs { private final List> writers = new ArrayList<>(); - @Override public MultipartCodecs encoder(Encoder encoder) { writer(new EncoderHttpMessageWriter<>(encoder)); diff --git a/spring-web/src/main/java/org/springframework/http/codec/DefaultServerCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/DefaultServerCodecConfigurer.java index cbe3c3fcaa..295c36b40c 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/DefaultServerCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/DefaultServerCodecConfigurer.java @@ -22,6 +22,7 @@ import java.util.List; import org.springframework.core.codec.Encoder; import org.springframework.http.codec.multipart.MultipartHttpMessageReader; import org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -32,16 +33,15 @@ import org.springframework.util.ClassUtils; */ class DefaultServerCodecConfigurer extends AbstractCodecConfigurer implements ServerCodecConfigurer { - static final boolean synchronossMultipartPresent = - ClassUtils.isPresent("org.synchronoss.cloud.nio.multipart.NioMultipartParser", - AbstractCodecConfigurer.class.getClassLoader()); + static final boolean synchronossMultipartPresent = ClassUtils.isPresent( + "org.synchronoss.cloud.nio.multipart.NioMultipartParser", + DefaultServerCodecConfigurer.class.getClassLoader()); public DefaultServerCodecConfigurer() { super(new ServerDefaultCodecsImpl()); } - @Override public ServerDefaultCodecs defaultCodecs() { return (ServerDefaultCodecs) super.defaultCodecs(); @@ -51,18 +51,16 @@ class DefaultServerCodecConfigurer extends AbstractCodecConfigurer implements Se /** * Default implementation of {@link ServerDefaultCodecs}. */ - private static class ServerDefaultCodecsImpl extends AbstractDefaultCodecs - implements ServerDefaultCodecs { + private static class ServerDefaultCodecsImpl extends AbstractDefaultCodecs implements ServerDefaultCodecs { + @Nullable private Encoder sseEncoder; - @Override public void serverSentEventEncoder(Encoder encoder) { this.sseEncoder = encoder; } - @Override protected boolean splitTextOnNewLine() { return true; diff --git a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java index 037e807a56..0b487c1b17 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java @@ -35,7 +35,6 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.lang.Nullable; import org.springframework.util.Assert; - /** * {@code HttpMessageWriter} that wraps and delegates to a {@link Encoder}. * @@ -54,6 +53,7 @@ public class EncoderHttpMessageWriter implements HttpMessageWriter { private final List mediaTypes; + @Nullable private final MediaType defaultMediaType; diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java index 734f7e33a2..3c89a1838f 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java @@ -34,7 +34,6 @@ import org.springframework.core.codec.Encoder; */ public interface ServerCodecConfigurer extends CodecConfigurer { - @Override ServerDefaultCodecs defaultCodecs(); diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java index 83e599cd01..542ee60f56 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java @@ -36,18 +36,25 @@ import org.springframework.lang.Nullable; */ public class ServerSentEvent { + @Nullable private final String id; + @Nullable private final String event; + @Nullable private final Duration retry; + @Nullable private final String comment; + @Nullable private final T data; - private ServerSentEvent(String id, String event, Duration retry, String comment, T data) { + private ServerSentEvent(@Nullable String id, @Nullable String event, @Nullable Duration retry, + @Nullable String comment, @Nullable T data) { + this.id = id; this.event = event; this.retry = retry; @@ -167,7 +174,7 @@ public class ServerSentEvent { * @param data the value of the data field * @return {@code this} builder */ - Builder data(T data); + Builder data(@Nullable T data); /** * Builds the event. @@ -179,14 +186,19 @@ public class ServerSentEvent { private static class BuilderImpl implements Builder { + @Nullable private String id; + @Nullable private String event; + @Nullable private Duration retry; + @Nullable private String comment; + @Nullable private T data; public BuilderImpl() { @@ -221,7 +233,7 @@ public class ServerSentEvent { } @Override - public Builder data(T data) { + public Builder data(@Nullable T data) { this.data = data; return this; } diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java index 1ec75a73cb..baa26ced9a 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java @@ -29,6 +29,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; +import org.springframework.core.codec.CodecException; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DataBuffer; @@ -39,12 +40,11 @@ import org.springframework.http.MediaType; import org.springframework.http.ReactiveHttpInputMessage; import org.springframework.lang.Nullable; -import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.*; /** * Reader that supports a stream of {@link ServerSentEvent}s and also plain - * {@link Object}s which is the same as an {@link ServerSentEvent} with data - * only. + * {@link Object}s which is the same as an {@link ServerSentEvent} with data only. * * @author Sebastien Deleuze * @author Rossen Stoyanchev @@ -59,6 +59,7 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader decoder; @@ -178,11 +179,16 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader hints) { if (String.class == dataType.resolve()) { return data.substring(0, data.length() - 1); } + if (this.decoder == null) { + return Flux.error(new CodecException("No SSE decoder configured and the data is not String.")); + } + byte[] bytes = data.getBytes(StandardCharsets.UTF_8); Mono input = Mono.just(bufferFactory.wrap(bytes)); diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java index 971400f4bf..c06f231b2b 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java @@ -48,10 +48,9 @@ import org.springframework.lang.Nullable; */ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter { - private static final List WRITABLE_MEDIA_TYPES = - Collections.singletonList(MediaType.TEXT_EVENT_STREAM); - + private static final List WRITABLE_MEDIA_TYPES = Collections.singletonList(MediaType.TEXT_EVENT_STREAM); + @Nullable private final Encoder encoder; diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java index 2ac71c3e2e..ec73736ffb 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java @@ -230,6 +230,7 @@ public class MultipartHttpMessageWriter implements HttpMessageWriter body; public MultipartHttpOutputMessage(DataBufferFactory bufferFactory, Charset charset) { diff --git a/spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java index 34fb1d9085..c259820a5a 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java @@ -70,8 +70,10 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter readableMediaTypes = new ArrayList<>(); + @Nullable private MediaType defaultContentType; + @Nullable private File cacheDir; @@ -112,6 +114,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter parts, byte[] boundary) throws IOException { diff --git a/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java index 0983cc0a8c..833d8f43ab 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/StringHttpMessageConverter.java @@ -45,6 +45,7 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter availableCharsets; private boolean writeAcceptCharset = true; @@ -110,11 +111,12 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter getAcceptedCharsets() { - if (this.availableCharsets == null) { - this.availableCharsets = new ArrayList<>( - Charset.availableCharsets().values()); + List charsets = this.availableCharsets; + if (charsets == null) { + charsets = new ArrayList<>(Charset.availableCharsets().values()); + this.availableCharsets = charsets; } - return this.availableCharsets; + return charsets; } private Charset getContentTypeCharset(@Nullable MediaType contentType) { diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java index 08c9c09df1..2871ca3584 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java @@ -71,8 +71,10 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener protected ObjectMapper objectMapper; + @Nullable private Boolean prettyPrint; + @Nullable private PrettyPrinter ssePrettyPrinter; @@ -119,6 +121,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener /** * Return the underlying {@code ObjectMapper} for this view. */ + @Nullable public ObjectMapper getObjectMapper() { return this.objectMapper; } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java index 772321888a..5e1baecfba 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJsonHttpMessageConverter.java @@ -52,6 +52,7 @@ public abstract class AbstractJsonHttpMessageConverter extends AbstractGenericHt public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + @Nullable private String jsonPrefix; diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/GsonFactoryBean.java b/spring-web/src/main/java/org/springframework/http/converter/json/GsonFactoryBean.java index 0c5f05530a..4ed089ec8b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/GsonFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/GsonFactoryBean.java @@ -23,6 +23,7 @@ import com.google.gson.GsonBuilder; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * A {@link FactoryBean} for creating a Google Gson 2.x {@link Gson} instance. @@ -41,8 +42,10 @@ public class GsonFactoryBean implements FactoryBean, InitializingBean { private boolean disableHtmlEscaping = false; + @Nullable private String dateFormatPattern; + @Nullable private Gson gson; diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index 02b8d89c0e..499122a855 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -59,6 +59,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.FatalBeanException; import org.springframework.context.ApplicationContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StreamUtils; @@ -107,26 +108,37 @@ public class Jackson2ObjectMapperBuilder { private boolean createXmlMapper = false; + @Nullable private JsonFactory factory; + @Nullable private DateFormat dateFormat; + @Nullable private Locale locale; + @Nullable private TimeZone timeZone; + @Nullable private AnnotationIntrospector annotationIntrospector; + @Nullable private PropertyNamingStrategy propertyNamingStrategy; + @Nullable private TypeResolverBuilder defaultTyping; + @Nullable private JsonInclude.Include serializationInclusion; + @Nullable private FilterProvider filters; + @Nullable private List modules; + @Nullable private Class[] moduleClasses; private boolean findModulesViaServiceLoader = false; @@ -135,10 +147,13 @@ public class Jackson2ObjectMapperBuilder { private ClassLoader moduleClassLoader = getClass().getClassLoader(); + @Nullable private HandlerInstantiator handlerInstantiator; + @Nullable private ApplicationContext applicationContext; + @Nullable private Boolean defaultUseWrapper; diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java index 7959a19fe9..f52578515b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java @@ -46,6 +46,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.lang.Nullable; /** * A {@link FactoryBean} for creating a Jackson 2.x {@link ObjectMapper} (default) or @@ -144,6 +145,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean deserializationView; - public MappingJacksonInputMessage(@Nullable InputStream body, HttpHeaders headers) { + public MappingJacksonInputMessage(InputStream body, HttpHeaders headers) { this.body = body; this.headers = headers; } - public MappingJacksonInputMessage(@Nullable InputStream body, HttpHeaders headers, Class deserializationView) { + public MappingJacksonInputMessage(InputStream body, HttpHeaders headers, Class deserializationView) { this(body, headers); this.deserializationView = deserializationView; } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/MappingJacksonValue.java b/spring-web/src/main/java/org/springframework/http/converter/json/MappingJacksonValue.java index d3a256902f..feaca4ddbe 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/MappingJacksonValue.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/MappingJacksonValue.java @@ -74,7 +74,7 @@ public class MappingJacksonValue { * @see com.fasterxml.jackson.databind.ObjectMapper#writerWithView(Class) * @see com.fasterxml.jackson.annotation.JsonView */ - public void setSerializationView(@Nullable Class serializationView) { + public void setSerializationView(Class serializationView) { this.serializationView = serializationView; } diff --git a/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java index 0d0bc25b08..ecb87985d1 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java @@ -91,6 +91,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter { + @Nullable private Marshaller marshaller; + @Nullable private Unmarshaller unmarshaller; diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.java index d21cd784d7..68ec1f8a50 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.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. @@ -24,6 +24,7 @@ import javax.servlet.AsyncListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -41,6 +42,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ private final ServletServerHttpResponse response; + @Nullable private AsyncContext asyncContext; private AtomicBoolean asyncCompleted = new AtomicBoolean(false); @@ -101,7 +103,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ @Override public void complete() { - if (isStarted() && !isCompleted()) { + if (this.asyncContext != null && isStarted() && !isCompleted()) { this.asyncContext.complete(); } } diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java index b2df7e9374..63e61dca38 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java @@ -40,6 +40,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.util.StringUtils; @@ -60,8 +61,10 @@ public class ServletServerHttpRequest implements ServerHttpRequest { private final HttpServletRequest servletRequest; + @Nullable private HttpHeaders headers; + @Nullable private ServerHttpAsyncRequestControl asyncRequestControl; diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java index 6df66b12f0..2d68f30d8e 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java @@ -56,6 +56,7 @@ public abstract class AbstractListenerReadPublisher implements Publisher { private static final AtomicLongFieldUpdater DEMAND_FIELD_UPDATER = AtomicLongFieldUpdater.newUpdater(AbstractListenerReadPublisher.class, "demand"); + @Nullable private Subscriber subscriber; @@ -126,6 +127,7 @@ public abstract class AbstractListenerReadPublisher implements Publisher { if (r != Long.MAX_VALUE) { DEMAND_FIELD_UPDATER.addAndGet(this, -1L); } + Assert.state(this.subscriber != null, "No subscriber"); this.subscriber.onNext(data); } else { @@ -144,7 +146,6 @@ public abstract class AbstractListenerReadPublisher implements Publisher { private final AbstractListenerReadPublisher publisher; - public ReadSubscription(AbstractListenerReadPublisher publisher) { this.publisher = publisher; } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java index 8970bd2ddd..262751b773 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java @@ -26,6 +26,7 @@ import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -48,6 +49,7 @@ public abstract class AbstractListenerWriteFlushProcessor implements Processo private volatile boolean subscriberCompleted; + @Nullable private Subscription subscription; @@ -105,8 +107,8 @@ public abstract class AbstractListenerWriteFlushProcessor implements Processo /** * Invoked when an error happens while flushing. Defaults to no-op. - * Servlet 3.1 based implementations will receive - * {@link AsyncListener#onError(Throwable)} event. + * Servlet 3.1 based implementations will receive an + * {@link javax.servlet.AsyncListener#onError} event. */ protected void flushingFailed(Throwable t) { } @@ -185,6 +187,7 @@ public abstract class AbstractListenerWriteFlushProcessor implements Processo } else { if (processor.changeState(this, REQUESTED)) { + Assert.state(processor.subscription != null, "No subscription"); processor.subscription.request(1); } } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java index a746456559..fa59a40be2 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java @@ -25,6 +25,7 @@ import org.reactivestreams.Processor; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -48,10 +49,12 @@ public abstract class AbstractListenerWriteProcessor implements Processor state = new AtomicReference<>(State.UNSUBSCRIBED); + @Nullable protected volatile T currentData; private volatile boolean subscriberCompleted; + @Nullable private Subscription subscription; @@ -145,8 +148,8 @@ public abstract class AbstractListenerWriteProcessor implements Processor implements Processor void onNext(AbstractListenerWriteProcessor processor, T data) { if (processor.isDataEmpty(data)) { + Assert.state(processor.subscription != null, "No subscription"); processor.subscription.request(1); } else { @@ -264,6 +268,7 @@ public abstract class AbstractListenerWriteProcessor implements Processor void onWritePossible(AbstractListenerWriteProcessor processor) { if (processor.changeState(this, WRITING)) { T data = processor.currentData; + Assert.state(data != null, "No data"); try { boolean writeCompleted = processor.write(data); if (writeCompleted) { @@ -271,6 +276,7 @@ public abstract class AbstractListenerWriteProcessor implements Processor queryParams; + @Nullable private MultiValueMap cookies; diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java index 47903c965c..63c93301d9 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java @@ -62,12 +62,14 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse { private final DataBufferFactory dataBufferFactory; + @Nullable private HttpStatus statusCode; private final HttpHeaders headers; private final MultiValueMap cookies; + @Nullable private Function urlEncoder = url -> url; private final AtomicReference state = new AtomicReference<>(State.NEW); @@ -105,6 +107,7 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse { } @Override + @Nullable public HttpStatus getStatusCode() { return this.statusCode; } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ChannelSendOperator.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ChannelSendOperator.java index 3ae420f8b1..8f5e5f555d 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ChannelSendOperator.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ChannelSendOperator.java @@ -45,7 +45,8 @@ import org.springframework.util.Assert; public class ChannelSendOperator extends Mono implements Scannable { private final Function, Publisher> writeFunction; - private final Flux source; + + private final Flux source; public ChannelSendOperator(Publisher source, Function, Publisher> writeFunction) { @@ -53,16 +54,20 @@ public class ChannelSendOperator extends Mono implements Scannable { this.writeFunction = writeFunction; } + @Override @Nullable @SuppressWarnings("rawtypes") public Object scanUnsafe(Attr key) { - if (key == IntAttr.PREFETCH) return Integer.MAX_VALUE; - if (key == ScannableAttr.PARENT) return source; + if (key == IntAttr.PREFETCH) { + return Integer.MAX_VALUE; + } + if (key == ScannableAttr.PARENT) { + return this.source; + } return null; } - @Override public void subscribe(Subscriber s, Context ctx) { this.source.subscribe(new WriteWithBarrier(s), ctx); @@ -83,15 +88,18 @@ public class ChannelSendOperator extends Mono implements Scannable { private boolean beforeFirstEmission = true; /** Cached signal before readyToWrite */ + @Nullable private T item; /** Cached 1st/2nd signal before readyToWrite */ + @Nullable private Throwable error; /** Cached 1st/2nd signal before readyToWrite */ private boolean completed = false; /** The actual writeSubscriber vs the downstream completion subscriber */ + @Nullable private Subscriber writeSubscriber; public WriteWithBarrier(Subscriber subscriber) { @@ -107,12 +115,12 @@ public class ChannelSendOperator extends Mono implements Scannable { @Override public void doNext(T item) { if (this.readyToWrite) { - this.writeSubscriber.onNext(item); + obtainWriteSubscriber().onNext(item); return; } synchronized (this) { if (this.readyToWrite) { - this.writeSubscriber.onNext(item); + obtainWriteSubscriber().onNext(item); } else if (this.beforeFirstEmission) { this.item = item; @@ -120,7 +128,9 @@ public class ChannelSendOperator extends Mono implements Scannable { writeFunction.apply(this).subscribe(new DownstreamBridge(downstream())); } else { - subscription.cancel(); + if (this.subscription != null) { + this.subscription.cancel(); + } downstream().onError(new IllegalStateException("Unexpected item.")); } } @@ -129,12 +139,12 @@ public class ChannelSendOperator extends Mono implements Scannable { @Override public void doError(Throwable ex) { if (this.readyToWrite) { - this.writeSubscriber.onError(ex); + obtainWriteSubscriber().onError(ex); return; } synchronized (this) { if (this.readyToWrite) { - this.writeSubscriber.onError(ex); + obtainWriteSubscriber().onError(ex); } else if (this.beforeFirstEmission) { this.beforeFirstEmission = false; @@ -149,12 +159,12 @@ public class ChannelSendOperator extends Mono implements Scannable { @Override public void doComplete() { if (this.readyToWrite) { - this.writeSubscriber.onComplete(); + obtainWriteSubscriber().onComplete(); return; } synchronized (this) { if (this.readyToWrite) { - this.writeSubscriber.onComplete(); + obtainWriteSubscriber().onComplete(); } else if (this.beforeFirstEmission) { this.completed = true; @@ -170,9 +180,8 @@ public class ChannelSendOperator extends Mono implements Scannable { @Override public void subscribe(Subscriber writeSubscriber) { synchronized (this) { - Assert.isNull(this.writeSubscriber, "Only one writeSubscriber supported"); + Assert.state(this.writeSubscriber == null, "Only one write subscriber supported"); this.writeSubscriber = writeSubscriber; - if (this.error != null || this.completed) { this.writeSubscriber.onSubscribe(Operators.emptySubscription()); emitCachedSignals(); @@ -189,14 +198,14 @@ public class ChannelSendOperator extends Mono implements Scannable { */ private boolean emitCachedSignals() { if (this.item != null) { - this.writeSubscriber.onNext(this.item); + obtainWriteSubscriber().onNext(this.item); } if (this.error != null) { - this.writeSubscriber.onError(this.error); + obtainWriteSubscriber().onError(this.error); return true; } if (this.completed) { - this.writeSubscriber.onComplete(); + obtainWriteSubscriber().onComplete(); return true; } return false; @@ -222,13 +231,20 @@ public class ChannelSendOperator extends Mono implements Scannable { } } } + + private Subscriber obtainWriteSubscriber() { + Assert.state(this.writeSubscriber != null, "No write subscriber"); + return this.writeSubscriber; + } } + // TODO Remove this copy of Reactor 3.0.x Operators.SubscriberAdapter private static class SubscriberAdapter implements Subscriber, Subscription { protected final Subscriber subscriber; + @Nullable protected Subscription subscription; public SubscriberAdapter(Subscriber subscriber) { @@ -236,15 +252,16 @@ public class ChannelSendOperator extends Mono implements Scannable { } public Subscriber downstream() { - return subscriber; + return this.subscriber; } @Override public final void cancel() { try { doCancel(); - } catch (Throwable throwable) { - doOnSubscriberError(Operators.onOperatorError(subscription, throwable)); + } + catch (Throwable throwable) { + doOnSubscriberError(Operators.onOperatorError(this.subscription, throwable)); } } @@ -252,7 +269,8 @@ public class ChannelSendOperator extends Mono implements Scannable { public final void onComplete() { try { doComplete(); - } catch (Throwable throwable) { + } + catch (Throwable throwable) { doOnSubscriberError(Operators.onOperatorError(throwable)); } } @@ -268,15 +286,15 @@ public class ChannelSendOperator extends Mono implements Scannable { doNext(i); } catch (Throwable throwable) { - doOnSubscriberError(Operators.onOperatorError(subscription, throwable, i)); + doOnSubscriberError(Operators.onOperatorError(this.subscription, throwable, i)); } } @Override public final void onSubscribe(Subscription s) { - if (Operators.validate(subscription, s)) { + if (Operators.validate(this.subscription, s)) { try { - subscription = s; + this.subscription = s; doOnSubscribe(s); } catch (Throwable throwable) { @@ -290,7 +308,8 @@ public class ChannelSendOperator extends Mono implements Scannable { try { Operators.checkRequest(n); doRequest(n); - } catch (Throwable throwable) { + } + catch (Throwable throwable) { doCancel(); doOnSubscriberError(Operators.onOperatorError(throwable)); } @@ -306,28 +325,29 @@ public class ChannelSendOperator extends Mono implements Scannable { * @param subscription the subscription to optionally process */ protected void doOnSubscribe(Subscription subscription) { - subscriber.onSubscribe(this); + this.subscriber.onSubscribe(this); } public Subscription upstream() { - return subscription; + Assert.state(this.subscription != null, "No subscription"); + return this.subscription; } @SuppressWarnings("unchecked") protected void doNext(I i) { - subscriber.onNext((O) i); + this.subscriber.onNext((O) i); } protected void doError(Throwable throwable) { - subscriber.onError(throwable); + this.subscriber.onError(throwable); } protected void doOnSubscriberError(Throwable throwable){ - subscriber.onError(throwable); + this.subscriber.onError(throwable); } protected void doComplete() { - subscriber.onComplete(); + this.subscriber.onComplete(); } protected void doRequest(long n) { diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java index 8607442735..9b8882ed47 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultRequestPath.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.http.server.reactive; import java.net.URI; @@ -38,19 +39,19 @@ class DefaultRequestPath implements RequestPath { private final PathSegmentContainer pathWithinApplication; - DefaultRequestPath(URI uri, String contextPath, Charset charset) { + DefaultRequestPath(URI uri, @Nullable String contextPath, Charset charset) { this.fullPath = PathSegmentContainer.parse(uri.getRawPath(), charset); this.contextPath = initContextPath(this.fullPath, contextPath); this.pathWithinApplication = extractPathWithinApplication(this.fullPath, this.contextPath); } - DefaultRequestPath(RequestPath requestPath, String contextPath) { + DefaultRequestPath(RequestPath requestPath, @Nullable String contextPath) { this.fullPath = requestPath; this.contextPath = initContextPath(this.fullPath, contextPath); this.pathWithinApplication = extractPathWithinApplication(this.fullPath, this.contextPath); } - private static PathSegmentContainer initContextPath(PathSegmentContainer path, String contextPath) { + private static PathSegmentContainer initContextPath(PathSegmentContainer path, @Nullable String contextPath) { if (!StringUtils.hasText(contextPath) || "/".equals(contextPath)) { return DefaultPathSegmentContainer.EMPTY_PATH; } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java index 459d757279..43b51c98a0 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java @@ -36,12 +36,16 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder { private final ServerHttpRequest delegate; + @Nullable private HttpMethod httpMethod; + @Nullable private String path; + @Nullable private String contextPath; + @Nullable private HttpHeaders httpHeaders; @@ -103,10 +107,10 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder { @Nullable private RequestPath getRequestPathToUse(@Nullable URI uriToUse) { - if (uriToUse == null && this.contextPath == null) { - return null; - } - else if (uriToUse == null) { + if (uriToUse == null) { + if (this.contextPath == null) { + return null; + } return new DefaultRequestPath(this.delegate.getPath(), this.contextPath); } else { @@ -134,18 +138,21 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder { */ private static class MutativeDecorator extends ServerHttpRequestDecorator { + @Nullable private final HttpMethod httpMethod; + @Nullable private final URI uri; + @Nullable private final RequestPath requestPath; + @Nullable private final HttpHeaders httpHeaders; - public MutativeDecorator(ServerHttpRequest delegate, HttpMethod method, - @Nullable URI uri, @Nullable RequestPath requestPath, - @Nullable HttpHeaders httpHeaders) { + public MutativeDecorator(ServerHttpRequest delegate, @Nullable HttpMethod method, + @Nullable URI uri, @Nullable RequestPath requestPath, @Nullable HttpHeaders httpHeaders) { super(delegate); this.httpMethod = method; diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java index f43f1c8ac4..a4a02ad67a 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java @@ -39,6 +39,7 @@ import org.springframework.core.io.buffer.DataBufferUtils; 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; /** @@ -53,8 +54,10 @@ public class ServletServerHttpResponse extends AbstractListenerServerHttpRespons private final int bufferSize; + @Nullable private volatile ResponseBodyFlushProcessor bodyFlushProcessor; + @Nullable private volatile ResponseBodyProcessor bodyProcessor; private volatile boolean flushOnNext; @@ -249,8 +252,9 @@ public class ServletServerHttpResponse extends AbstractListenerServerHttpRespons protected Processor createWriteProcessor() { try { ServletOutputStream outputStream = response.getOutputStream(); - bodyProcessor = new ResponseBodyProcessor(outputStream); - return bodyProcessor; + ResponseBodyProcessor processor = new ResponseBodyProcessor(outputStream); + bodyProcessor = processor; + return processor; } catch (IOException ex) { throw new UncheckedIOException(ex); diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpRequest.java index f43e0aaf54..502d8089a6 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpRequest.java @@ -33,6 +33,7 @@ import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -115,6 +116,7 @@ public class UndertowServerHttpRequest extends AbstractServerHttpRequest { private final ByteBufferPool byteBufferPool; + @Nullable private PooledByteBuffer pooledByteBuffer; public RequestBodyPublisher(HttpServerExchange exchange, DataBufferFactory bufferFactory) { diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java index 1d2358611d..d0bc832fa6 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java @@ -40,6 +40,7 @@ import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseCookie; import org.springframework.http.ZeroCopyHttpOutputMessage; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -55,6 +56,7 @@ public class UndertowServerHttpResponse extends AbstractListenerServerHttpRespon private final HttpServerExchange exchange; + @Nullable private StreamSinkChannel responseChannel; @@ -150,6 +152,7 @@ public class UndertowServerHttpResponse extends AbstractListenerServerHttpRespon private final StreamSinkChannel channel; + @Nullable private volatile ByteBuffer byteBuffer; public ResponseBodyProcessor(StreamSinkChannel channel) { @@ -171,14 +174,15 @@ public class UndertowServerHttpResponse extends AbstractListenerServerHttpRespon @Override protected boolean write(DataBuffer dataBuffer) throws IOException { - if (this.byteBuffer == null) { + ByteBuffer buffer = this.byteBuffer; + if (buffer == null) { return false; } if (logger.isTraceEnabled()) { logger.trace("write: " + dataBuffer); } - int total = this.byteBuffer.remaining(); - int written = writeByteBuffer(this.byteBuffer); + int total = buffer.remaining(); + int written = writeByteBuffer(buffer); if (logger.isTraceEnabled()) { logger.trace("written: " + written + " total: " + total); diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java b/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java index cd9b59a7cd..b087261d79 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java @@ -25,6 +25,7 @@ import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import reactor.core.publisher.Operators; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -40,10 +41,12 @@ class WriteResultPublisher implements Publisher { private final AtomicReference state = new AtomicReference<>(State.UNSUBSCRIBED); + @Nullable private Subscriber subscriber; private volatile boolean publisherCompleted; + @Nullable private volatile Throwable publisherError; @@ -123,8 +126,11 @@ class WriteResultPublisher implements Publisher { if (publisher.publisherCompleted) { publisher.publishComplete(); } - else if (publisher.publisherError != null) { - publisher.publishError(publisher.publisherError); + else { + Throwable publisherError = publisher.publisherError; + if (publisherError != null) { + publisher.publishError(publisherError); + } } } else { @@ -149,12 +155,14 @@ class WriteResultPublisher implements Publisher { @Override void publishComplete(WriteResultPublisher publisher) { if (publisher.changeState(this, COMPLETED)) { + Assert.state(publisher.subscriber != null, "No subscriber"); publisher.subscriber.onComplete(); } } @Override void publishError(WriteResultPublisher publisher, Throwable t) { if (publisher.changeState(this, COMPLETED)) { + Assert.state(publisher.subscriber != null, "No subscriber"); publisher.subscriber.onError(t); } } diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianClientInterceptor.java b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianClientInterceptor.java index 6463411b7c..fd95a9a618 100644 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianClientInterceptor.java +++ b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianClientInterceptor.java @@ -68,6 +68,7 @@ public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements private HessianProxyFactory proxyFactory = new HessianProxyFactory(); + @Nullable private Object hessianProxy; diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianExporter.java b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianExporter.java index 049d0bf53f..6e3c527e26 100644 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianExporter.java +++ b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianExporter.java @@ -62,10 +62,13 @@ public class HessianExporter extends RemoteExporter implements InitializingBean private SerializerFactory serializerFactory = new SerializerFactory(); + @Nullable private HessianRemoteResolver remoteResolver; + @Nullable private Log debugLogger; + @Nullable private HessianSkeleton skeleton; @@ -212,10 +215,8 @@ public class HessianExporter extends RemoteExporter implements InitializingBean throw new IOException("Expected 'H'/'C' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at " + code); } - if (this.serializerFactory != null) { - in.setSerializerFactory(this.serializerFactory); - out.setSerializerFactory(this.serializerFactory); - } + in.setSerializerFactory(this.serializerFactory); + out.setSerializerFactory(this.serializerFactory); if (this.remoteResolver != null) { in.setRemoteResolver(this.remoteResolver); } diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java index 0b9beb9f4e..d48e41614c 100644 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java +++ b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java @@ -73,6 +73,7 @@ public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvoke private HttpClient httpClient; + @Nullable private RequestConfig requestConfig; diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java index 3ff5a0f442..26a0c6e1c9 100644 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java +++ b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java @@ -73,8 +73,10 @@ import org.springframework.remoting.support.RemoteInvocationResult; public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor implements MethodInterceptor, HttpInvokerClientConfiguration { + @Nullable private String codebaseUrl; + @Nullable private HttpInvokerRequestExecutor httpInvokerRequestExecutor; @@ -98,6 +100,7 @@ public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor * Return the codebase URL to download classes from if not found locally. */ @Override + @Nullable public String getCodebaseUrl() { return this.codebaseUrl; } diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java index e5cb25316b..782122bf2d 100644 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java +++ b/spring-web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.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,8 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Abstract exporter for JAX-WS services, autodetecting annotated service beans @@ -50,14 +52,19 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; */ public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, InitializingBean, DisposableBean { + @Nullable private Map endpointProperties; + @Nullable private Executor executor; + @Nullable private String bindingType; + @Nullable private WebServiceFeature[] endpointFeatures; + @Nullable private ListableBeanFactory beanFactory; private final Set publishedEndpoints = new LinkedHashSet<>(); @@ -127,11 +134,14 @@ public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, * @see #publishEndpoint */ public void publishEndpoints() { + Assert.state(this.beanFactory != null, "No BeanFactory set"); + Set beanNames = new LinkedHashSet<>(this.beanFactory.getBeanDefinitionCount()); beanNames.addAll(Arrays.asList(this.beanFactory.getBeanDefinitionNames())); if (this.beanFactory instanceof ConfigurableBeanFactory) { beanNames.addAll(Arrays.asList(((ConfigurableBeanFactory) this.beanFactory).getSingletonNames())); } + for (String beanName : beanNames) { try { Class type = this.beanFactory.getType(beanName); diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java index be1ffef0a8..ad299222d3 100644 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java +++ b/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java @@ -65,34 +65,46 @@ import org.springframework.util.StringUtils; public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory implements MethodInterceptor, BeanClassLoaderAware, InitializingBean { + @Nullable private Service jaxWsService; + @Nullable private String portName; + @Nullable private String username; + @Nullable private String password; + @Nullable private String endpointAddress; private boolean maintainSession; private boolean useSoapAction; + @Nullable private String soapActionUri; + @Nullable private Map customProperties; + @Nullable private WebServiceFeature[] portFeatures; + @Nullable private Class serviceInterface; private boolean lookupServiceOnStartup = true; + @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @Nullable private QName portQName; + @Nullable private Object portStub; private final Object preparationMonitor = new Object(); @@ -286,6 +298,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory /** * Return the interface of the service that this factory should create a proxy for. */ + @Nullable public Class getServiceInterface() { return this.serviceInterface; } @@ -312,6 +325,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory /** * Return the bean ClassLoader to use for this interceptor. */ + @Nullable protected ClassLoader getBeanClassLoader() { return this.beanClassLoader; } @@ -402,6 +416,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory * @see #setPortName * @see #getQName */ + @Nullable protected final QName getPortQName() { return this.portQName; } @@ -472,6 +487,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory * Return the underlying JAX-WS port stub that this interceptor delegates to * for each method invocation on the proxy. */ + @Nullable protected Object getPortStub() { return this.portStub; } @@ -526,7 +542,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory * @see #getPortStub() */ @Nullable - protected Object doInvoke(MethodInvocation invocation, Object portStub) throws Throwable { + protected Object doInvoke(MethodInvocation invocation, @Nullable Object portStub) throws Throwable { Method method = invocation.getMethod(); try { return method.invoke(portStub, invocation.getArguments()); diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java index c3db95288c..7a4615c7c5 100644 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java +++ b/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java @@ -44,16 +44,22 @@ import org.springframework.util.Assert; */ public class LocalJaxWsServiceFactory { + @Nullable private URL wsdlDocumentUrl; + @Nullable private String namespaceUri; + @Nullable private String serviceName; + @Nullable private WebServiceFeature[] serviceFeatures; + @Nullable private Executor executor; + @Nullable private HandlerResolver handlerResolver; diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java index 677d6fadb4..315ff67921 100644 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.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,6 +20,7 @@ import javax.xml.ws.Service; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; /** * {@link org.springframework.beans.factory.FactoryBean} for locally @@ -38,6 +39,7 @@ import org.springframework.beans.factory.InitializingBean; public class LocalJaxWsServiceFactoryBean extends LocalJaxWsServiceFactory implements FactoryBean, InitializingBean { + @Nullable private Service service; diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java index 5b5414158f..1c8fbad4b5 100644 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java +++ b/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.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. @@ -29,7 +29,9 @@ import com.sun.net.httpserver.HttpServer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.lang.Nullable; import org.springframework.lang.UsesSunHttpServer; +import org.springframework.util.Assert; /** * Simple exporter for JAX-WS services, autodetecting annotated service beans @@ -53,10 +55,12 @@ public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceEx protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private HttpServer server; private int port = 8080; + @Nullable private String hostname; private int backlog = -1; @@ -65,8 +69,10 @@ public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceEx private String basePath = "/"; + @Nullable private List filters; + @Nullable private Authenticator authenticator; private boolean localServer = false; @@ -157,11 +163,12 @@ public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceEx if (this.server == null) { InetSocketAddress address = (this.hostname != null ? new InetSocketAddress(this.hostname, this.port) : new InetSocketAddress(this.port)); - this.server = HttpServer.create(address, this.backlog); + HttpServer server = HttpServer.create(address, this.backlog); if (this.logger.isInfoEnabled()) { this.logger.info("Starting HttpServer at address " + address); } - this.server.start(); + server.start(); + this.server = server; this.localServer = true; } super.afterPropertiesSet(); @@ -184,6 +191,7 @@ public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceEx * @return the fully populated HttpContext */ protected HttpContext buildHttpContext(Endpoint endpoint, String serviceName) { + Assert.state(this.server != null, "No HttpServer available"); String fullPath = calculateEndpointPath(endpoint, serviceName); HttpContext httpContext = this.server.createContext(fullPath); if (this.filters != null) { @@ -209,7 +217,7 @@ public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceEx @Override public void destroy() { super.destroy(); - if (this.localServer) { + if (this.server != null && this.localServer) { logger.info("Stopping HttpServer"); this.server.stop(this.shutdownDelay); } diff --git a/spring-web/src/main/java/org/springframework/web/HttpMediaTypeNotSupportedException.java b/spring-web/src/main/java/org/springframework/web/HttpMediaTypeNotSupportedException.java index fbb92286a5..1a0ff2a731 100644 --- a/spring-web/src/main/java/org/springframework/web/HttpMediaTypeNotSupportedException.java +++ b/spring-web/src/main/java/org/springframework/web/HttpMediaTypeNotSupportedException.java @@ -31,6 +31,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class HttpMediaTypeNotSupportedException extends HttpMediaTypeException { + @Nullable private final MediaType contentType; @@ -67,6 +68,7 @@ public class HttpMediaTypeNotSupportedException extends HttpMediaTypeException { /** * Return the HTTP request content type method that caused the failure. */ + @Nullable public MediaType getContentType() { return this.contentType; } diff --git a/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java b/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java index 1b42d978b6..ef2e3fc0e8 100644 --- a/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java +++ b/spring-web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java @@ -39,6 +39,7 @@ public class HttpRequestMethodNotSupportedException extends ServletException { private String method; + @Nullable private String[] supportedMethods; diff --git a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java index 183f3bdac5..7a1a25978e 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManagerFactoryBean.java @@ -101,14 +101,18 @@ public class ContentNegotiationManagerFactoryBean private boolean ignoreUnknownPathExtensions = true; + @Nullable private Boolean useRegisteredExtensionsOnly; private String parameterName = "format"; + @Nullable private ContentNegotiationStrategy defaultNegotiationStrategy; + @Nullable private ContentNegotiationManager contentNegotiationManager; + @Nullable private ServletContext servletContext; @@ -268,13 +272,12 @@ public class ContentNegotiationManagerFactoryBean } - public ContentNegotiationManager build() { - afterPropertiesSet(); - return this.contentNegotiationManager; - } - @Override public void afterPropertiesSet() { + build(); + } + + public ContentNegotiationManager build() { List strategies = new ArrayList<>(); if (this.favorPathExtension) { @@ -309,8 +312,10 @@ public class ContentNegotiationManagerFactoryBean } this.contentNegotiationManager = new ContentNegotiationManager(strategies); + return this.contentNegotiationManager; } + @Override public ContentNegotiationManager getObject() { return this.contentNegotiationManager; diff --git a/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java b/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java index ac175852ba..e3930d450b 100644 --- a/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java +++ b/spring-web/src/main/java/org/springframework/web/accept/ServletPathExtensionContentNegotiationStrategy.java @@ -17,7 +17,6 @@ package org.springframework.web.accept; import java.util.Map; - import javax.servlet.ServletContext; import org.springframework.core.io.Resource; @@ -72,11 +71,9 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio throws HttpMediaTypeNotAcceptableException { MediaType mediaType = null; - if (this.servletContext != null) { - String mimeType = this.servletContext.getMimeType("file." + extension); - if (StringUtils.hasText(mimeType)) { - mediaType = MediaType.parseMediaType(mimeType); - } + String mimeType = this.servletContext.getMimeType("file." + extension); + if (StringUtils.hasText(mimeType)) { + mediaType = MediaType.parseMediaType(mimeType); } if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { MediaType superMediaType = super.handleNoMatch(webRequest, extension); @@ -98,11 +95,9 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio @Override public MediaType getMediaTypeForResource(Resource resource) { MediaType mediaType = null; - if (this.servletContext != null) { - String mimeType = this.servletContext.getMimeType(resource.getFilename()); - if (StringUtils.hasText(mimeType)) { - mediaType = MediaType.parseMediaType(mimeType); - } + String mimeType = this.servletContext.getMimeType(resource.getFilename()); + if (StringUtils.hasText(mimeType)) { + mediaType = MediaType.parseMediaType(mimeType); } if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { MediaType superMediaType = super.getMediaTypeForResource(resource); diff --git a/spring-web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java index 4dc9c932ef..7937f948e9 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/ServletRequestDataBinder.java @@ -75,7 +75,7 @@ public class ServletRequestDataBinder extends WebDataBinder { * if the binder is just used to convert a plain parameter value) * @param objectName the name of the target object */ - public ServletRequestDataBinder(@Nullable Object target, @Nullable String objectName) { + public ServletRequestDataBinder(@Nullable Object target, String objectName) { super(target, objectName); } diff --git a/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java index 9b22a7f7a4..c7c8a795cc 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java @@ -98,7 +98,7 @@ public class WebDataBinder extends DataBinder { * if the binder is just used to convert a plain parameter value) * @param objectName the name of the target object */ - public WebDataBinder(@Nullable Object target, @Nullable String objectName) { + public WebDataBinder(@Nullable Object target, String objectName) { super(target, objectName); } diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/ConfigurableWebBindingInitializer.java b/spring-web/src/main/java/org/springframework/web/bind/support/ConfigurableWebBindingInitializer.java index 5781908384..5cdb13b3fa 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/ConfigurableWebBindingInitializer.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/ConfigurableWebBindingInitializer.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. @@ -44,14 +44,19 @@ public class ConfigurableWebBindingInitializer implements WebBindingInitializer private boolean directFieldAccess = false; + @Nullable private MessageCodesResolver messageCodesResolver; + @Nullable private BindingErrorProcessor bindingErrorProcessor; + @Nullable private Validator validator; + @Nullable private ConversionService conversionService; + @Nullable private PropertyEditorRegistrar[] propertyEditorRegistrars; diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.java b/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.java index 3220343ecd..7a6deec9d8 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.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. @@ -29,6 +29,7 @@ import org.springframework.web.context.request.NativeWebRequest; */ public class DefaultDataBinderFactory implements WebDataBinderFactory { + @Nullable private final WebBindingInitializer initializer; @@ -49,8 +50,8 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory { */ @Override @SuppressWarnings("deprecation") - public final WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, - @Nullable String objectName) throws Exception { + public final WebDataBinder createBinder( + NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception { WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest); if (this.initializer != null) { @@ -69,7 +70,7 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory { * @throws Exception in case of invalid state or arguments */ protected WebDataBinder createBinderInstance( - @Nullable Object target, @Nullable String objectName, NativeWebRequest webRequest) throws Exception { + @Nullable Object target, String objectName, NativeWebRequest webRequest) throws Exception { return new WebRequestDataBinder(target, objectName); } diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebDataBinderFactory.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebDataBinderFactory.java index 45c1b0b168..e7c6f3d669 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebDataBinderFactory.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebDataBinderFactory.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. @@ -31,11 +31,13 @@ public interface WebDataBinderFactory { /** * Create a {@link WebDataBinder} for the given object. * @param webRequest the current request - * @param target the object to create a data binder for, or {@code null} if creating a binder for a simple type + * @param target the object to create a data binder for, + * or {@code null} if creating a binder for a simple type * @param objectName the name of the target object * @return the created {@link WebDataBinder} instance, never null * @throws Exception raised if the creation and initialization of the data binder fails */ - WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, @Nullable String objectName) throws Exception; + WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName) + throws Exception; } diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java index 7ff87b54f7..18dee84b44 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java @@ -41,7 +41,6 @@ import org.springframework.web.server.ServerWebExchange; */ public class WebExchangeDataBinder extends WebDataBinder { - /** * Create a new instance, with default object name. * @param target the target object to bind onto (or {@code null} if the @@ -86,12 +85,10 @@ public class WebExchangeDataBinder extends WebDataBinder { * Combine query params and form data for multipart form data from the body * of the request into a {@code Map} of values to use for * data binding purposes. - * * @param exchange the current exchange * @return a {@code Mono} with the values to bind */ public static Mono> extractValuesToBind(ServerWebExchange exchange) { - MultiValueMap queryParams = exchange.getRequest().getQueryParams(); Mono> formData = exchange.getFormData(); Mono> multipartData = exchange.getMultipartData(); diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java index c9a581ee0f..b0c40c40e7 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java @@ -86,7 +86,7 @@ public class WebRequestDataBinder extends WebDataBinder { * if the binder is just used to convert a plain parameter value) * @param objectName the name of the target object */ - public WebRequestDataBinder(@Nullable Object target, @Nullable String objectName) { + public WebRequestDataBinder(@Nullable Object target, String objectName) { super(target, objectName); } diff --git a/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java index 2063763461..d03be0125d 100644 --- a/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java @@ -593,6 +593,7 @@ public class AsyncRestTemplate extends org.springframework.http.client.support.I private final URI url; + @Nullable private final ResponseExtractor responseExtractor; public ResponseExtractorFuture(HttpMethod method, URI url, diff --git a/spring-web/src/main/java/org/springframework/web/client/HttpMessageConverterExtractor.java b/spring-web/src/main/java/org/springframework/web/client/HttpMessageConverterExtractor.java index 837796aee6..9b40e9af6f 100644 --- a/spring-web/src/main/java/org/springframework/web/client/HttpMessageConverterExtractor.java +++ b/spring-web/src/main/java/org/springframework/web/client/HttpMessageConverterExtractor.java @@ -28,6 +28,7 @@ import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -42,6 +43,7 @@ public class HttpMessageConverterExtractor implements ResponseExtractor { private final Type responseType; + @Nullable private final Class responseClass; private final List> messageConverters; diff --git a/spring-web/src/main/java/org/springframework/web/client/MessageBodyClientHttpResponseWrapper.java b/spring-web/src/main/java/org/springframework/web/client/MessageBodyClientHttpResponseWrapper.java index c195749fc8..9ebe5651cb 100644 --- a/spring-web/src/main/java/org/springframework/web/client/MessageBodyClientHttpResponseWrapper.java +++ b/spring-web/src/main/java/org/springframework/web/client/MessageBodyClientHttpResponseWrapper.java @@ -23,6 +23,7 @@ import java.io.PushbackInputStream; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.Nullable; /** * Implementation of {@link ClientHttpResponse} that can not only check if @@ -31,12 +32,13 @@ import org.springframework.http.client.ClientHttpResponse; * * @author Brian Clozel * @since 4.1.5 - * @see rfc7230 Section 3.3.3 + * @see RFC 7230 Section 3.3.3 */ class MessageBodyClientHttpResponseWrapper implements ClientHttpResponse { private final ClientHttpResponse response; + @Nullable private PushbackInputStream pushbackInputStream; diff --git a/spring-web/src/main/java/org/springframework/web/client/RestClientResponseException.java b/spring-web/src/main/java/org/springframework/web/client/RestClientResponseException.java index f0eba4d561..079eb7dadc 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestClientResponseException.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestClientResponseException.java @@ -42,8 +42,10 @@ public class RestClientResponseException extends RestClientException { private final byte[] responseBody; + @Nullable private final HttpHeaders responseHeaders; + @Nullable private final String responseCharset; @@ -84,6 +86,7 @@ public class RestClientResponseException extends RestClientException { /** * Return the HTTP response headers. */ + @Nullable public HttpHeaders getResponseHeaders() { return this.responseHeaders; } diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java index a20d41380a..d1c8de28a1 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java @@ -783,6 +783,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat */ private class AcceptHeaderRequestCallback implements RequestCallback { + @Nullable private final Type responseType; private AcceptHeaderRequestCallback(@Nullable Type responseType) { @@ -937,6 +938,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat */ private class ResponseEntityResponseExtractor implements ResponseExtractor> { + @Nullable private final HttpMessageConverterExtractor delegate; public ResponseEntityResponseExtractor(@Nullable Type responseType) { diff --git a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java index 8423dd26c6..4286993c87 100644 --- a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java +++ b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java @@ -158,12 +158,14 @@ public class ContextLoader { * The 'current' WebApplicationContext, if the ContextLoader class is * deployed in the web app ClassLoader itself. */ + @Nullable private static volatile WebApplicationContext currentContext; /** * The root WebApplicationContext instance that this loader manages. */ + @Nullable private WebApplicationContext context; /** Actual ApplicationContextInitializer instances to apply to the context */ diff --git a/spring-web/src/main/java/org/springframework/web/context/request/ServletRequestAttributes.java b/spring-web/src/main/java/org/springframework/web/context/request/ServletRequestAttributes.java index 13e6487754..78d995930d 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/ServletRequestAttributes.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/ServletRequestAttributes.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. @@ -62,8 +62,10 @@ public class ServletRequestAttributes extends AbstractRequestAttributes { private final HttpServletRequest request; + @Nullable private HttpServletResponse response; + @Nullable private volatile HttpSession session; private final Map sessionAttributesToUpdate = new ConcurrentHashMap<>(1); diff --git a/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java index 763be5fb2e..b6b5fe3467 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java @@ -24,9 +24,11 @@ import org.springframework.context.support.AbstractRefreshableConfigApplicationC import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.lang.Nullable; import org.springframework.ui.context.Theme; import org.springframework.ui.context.ThemeSource; import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.util.Assert; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.ConfigurableWebEnvironment; import org.springframework.web.context.ServletConfigAware; @@ -80,15 +82,19 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR implements ConfigurableWebApplicationContext, ThemeSource { /** Servlet context that this context runs in */ + @Nullable private ServletContext servletContext; /** Servlet config that this context runs in, if any */ + @Nullable private ServletConfig servletConfig; /** Namespace of this context, or {@code null} if root */ + @Nullable private String namespace; /** the ThemeSource for this ApplicationContext */ + @Nullable private ThemeSource themeSource; @@ -103,6 +109,7 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR } @Override + @Nullable public ServletContext getServletContext() { return this.servletContext; } @@ -116,6 +123,7 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR } @Override + @Nullable public ServletConfig getServletConfig() { return this.servletConfig; } @@ -127,6 +135,7 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR } @Override + @Nullable public String getNamespace() { return this.namespace; } @@ -169,6 +178,7 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR */ @Override protected Resource getResourceByPath(String path) { + Assert.state(this.servletContext != null, "No ServletContext available"); return new ServletContextResource(this.servletContext, path); } @@ -203,6 +213,7 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR @Override public Theme getTheme(String themeName) { + Assert.state(this.themeSource != null, "No ThemeSource available"); return this.themeSource.getTheme(themeName); } diff --git a/spring-web/src/main/java/org/springframework/web/context/support/ContextExposingHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/context/support/ContextExposingHttpServletRequest.java index a2e3d001ed..34ccda3b29 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/ContextExposingHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/ContextExposingHttpServletRequest.java @@ -37,8 +37,10 @@ public class ContextExposingHttpServletRequest extends HttpServletRequestWrapper private final WebApplicationContext webApplicationContext; + @Nullable private final Set exposedContextBeanNames; + @Nullable private Set explicitAttributes; diff --git a/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java index 5ad925d5fb..91a97153ee 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.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. @@ -29,6 +29,7 @@ import org.springframework.lang.Nullable; import org.springframework.ui.context.Theme; import org.springframework.ui.context.ThemeSource; import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.context.ConfigurableWebApplicationContext; @@ -64,8 +65,10 @@ import org.springframework.web.context.ServletContextAware; public class GenericWebApplicationContext extends GenericApplicationContext implements ConfigurableWebApplicationContext, ThemeSource { + @Nullable private ServletContext servletContext; + @Nullable private ThemeSource themeSource; @@ -122,6 +125,7 @@ public class GenericWebApplicationContext extends GenericApplicationContext } @Override + @Nullable public ServletContext getServletContext() { return this.servletContext; } @@ -145,9 +149,10 @@ public class GenericWebApplicationContext extends GenericApplicationContext */ @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext)); - beanFactory.ignoreDependencyInterface(ServletContextAware.class); - + if (this.servletContext != null) { + beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext)); + beanFactory.ignoreDependencyInterface(ServletContextAware.class); + } WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext); } @@ -158,6 +163,7 @@ public class GenericWebApplicationContext extends GenericApplicationContext */ @Override protected Resource getResourceByPath(String path) { + Assert.state(this.servletContext != null, "No ServletContext available"); return new ServletContextResource(this.servletContext, path); } @@ -192,6 +198,7 @@ public class GenericWebApplicationContext extends GenericApplicationContext @Override public Theme getTheme(String themeName) { + Assert.state(this.themeSource != null, "No ThemeSource available"); return this.themeSource.getTheme(themeName); } diff --git a/spring-web/src/main/java/org/springframework/web/context/support/RequestHandledEvent.java b/spring-web/src/main/java/org/springframework/web/context/support/RequestHandledEvent.java index bbb3ce7ff3..449147924a 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/RequestHandledEvent.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/RequestHandledEvent.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. @@ -38,15 +38,18 @@ import org.springframework.lang.Nullable; public class RequestHandledEvent extends ApplicationEvent { /** Session id that applied to the request, if any */ + @Nullable private String sessionId; /** Usually the UserPrincipal */ + @Nullable private String userName; /** Request processing time */ private final long processingTimeMillis; /** Cause of failure, if any */ + @Nullable private Throwable failureCause; diff --git a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAttributeFactoryBean.java b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAttributeFactoryBean.java index 5e2d1d0029..8e42e573dc 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAttributeFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAttributeFactoryBean.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. @@ -19,6 +19,7 @@ package org.springframework.web.context.support; import javax.servlet.ServletContext; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.web.context.ServletContextAware; /** @@ -43,8 +44,10 @@ import org.springframework.web.context.ServletContextAware; */ public class ServletContextAttributeFactoryBean implements FactoryBean, ServletContextAware { + @Nullable private String attributeName; + @Nullable private Object attribute; diff --git a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAwareProcessor.java b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAwareProcessor.java index c2e75e566e..0883d27278 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAwareProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextAwareProcessor.java @@ -41,8 +41,10 @@ import org.springframework.web.context.ServletContextAware; */ public class ServletContextAwareProcessor implements BeanPostProcessor { + @Nullable private ServletContext servletContext; + @Nullable private ServletConfig servletConfig; diff --git a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextParameterFactoryBean.java b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextParameterFactoryBean.java index 27f30651ea..73cfbbbeae 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextParameterFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextParameterFactoryBean.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. @@ -19,6 +19,7 @@ package org.springframework.web.context.support; import javax.servlet.ServletContext; import org.springframework.beans.factory.FactoryBean; +import org.springframework.lang.Nullable; import org.springframework.web.context.ServletContextAware; /** @@ -38,8 +39,10 @@ import org.springframework.web.context.ServletContextAware; */ public class ServletContextParameterFactoryBean implements FactoryBean, ServletContextAware { + @Nullable private String initParamName; + @Nullable private String paramValue; diff --git a/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java index 4c262c5e81..c0a28192f3 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java @@ -24,9 +24,11 @@ import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.lang.Nullable; import org.springframework.ui.context.Theme; import org.springframework.ui.context.ThemeSource; import org.springframework.ui.context.support.UiApplicationContextUtils; +import org.springframework.util.Assert; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.ServletConfigAware; import org.springframework.web.context.ServletContextAware; @@ -56,12 +58,16 @@ import org.springframework.web.context.ServletContextAware; public class StaticWebApplicationContext extends StaticApplicationContext implements ConfigurableWebApplicationContext, ThemeSource { + @Nullable private ServletContext servletContext; + @Nullable private ServletConfig servletConfig; + @Nullable private String namespace; + @Nullable private ThemeSource themeSource; @@ -79,6 +85,7 @@ public class StaticWebApplicationContext extends StaticApplicationContext } @Override + @Nullable public ServletContext getServletContext() { return this.servletContext; } @@ -92,6 +99,7 @@ public class StaticWebApplicationContext extends StaticApplicationContext } @Override + @Nullable public ServletConfig getServletConfig() { return this.servletConfig; } @@ -103,6 +111,7 @@ public class StaticWebApplicationContext extends StaticApplicationContext } @Override + @Nullable public String getNamespace() { return this.namespace; } @@ -150,6 +159,7 @@ public class StaticWebApplicationContext extends StaticApplicationContext */ @Override protected Resource getResourceByPath(String path) { + Assert.state(this.servletContext != null, "No ServletContext available"); return new ServletContextResource(this.servletContext, path); } @@ -186,6 +196,7 @@ public class StaticWebApplicationContext extends StaticApplicationContext @Override public Theme getTheme(String themeName) { + Assert.state(this.themeSource != null, "No ThemeSource available"); return this.themeSource.getTheme(themeName); } diff --git a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java index fcd307ccdc..58250012d3 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java @@ -205,7 +205,7 @@ public abstract class WebApplicationContextUtils { * @param bf the BeanFactory to configure * @param sc the ServletContext that we're running within */ - public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, ServletContext sc) { + public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, @Nullable ServletContext sc) { registerEnvironmentBeans(bf, sc, null); } diff --git a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java index 4be4a59b50..8a7bb8235d 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java @@ -42,6 +42,7 @@ import org.springframework.web.util.WebUtils; */ public abstract class WebApplicationObjectSupport extends ApplicationObjectSupport implements ServletContextAware { + @Nullable private ServletContext servletContext; diff --git a/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java b/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java index 6c3ac18805..c78e89af39 100644 --- a/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java +++ b/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java @@ -65,18 +65,25 @@ public class CorsConfiguration { } + @Nullable private List allowedOrigins; + @Nullable private List allowedMethods; + @Nullable private List resolvedMethods = DEFAULT_METHODS; + @Nullable private List allowedHeaders; + @Nullable private List exposedHeaders; + @Nullable private Boolean allowCredentials; + @Nullable private Long maxAge; diff --git a/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java b/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java index afdf44cf7e..d2581760de 100644 --- a/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java +++ b/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java @@ -17,7 +17,6 @@ package org.springframework.web.filter; import java.io.IOException; - import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -82,14 +81,18 @@ import org.springframework.web.context.support.WebApplicationContextUtils; */ public class DelegatingFilterProxy extends GenericFilterBean { + @Nullable private String contextAttribute; + @Nullable private WebApplicationContext webApplicationContext; + @Nullable private String targetBeanName; private boolean targetFilterLifecycle = false; + @Nullable private volatile Filter delegate; private final Object delegateMonitor = new Object(); @@ -117,7 +120,7 @@ public class DelegatingFilterProxy extends GenericFilterBean { * @see #setEnvironment(org.springframework.core.env.Environment) */ public DelegatingFilterProxy(Filter delegate) { - Assert.notNull(delegate, "delegate Filter object must not be null"); + Assert.notNull(delegate, "Delegate Filter must not be null"); this.delegate = delegate; } @@ -197,6 +200,7 @@ public class DelegatingFilterProxy extends GenericFilterBean { /** * Return the name of the target bean in the Spring application context. */ + @Nullable protected String getTargetBeanName() { return this.targetBeanName; } @@ -249,15 +253,16 @@ public class DelegatingFilterProxy extends GenericFilterBean { Filter delegateToUse = this.delegate; if (delegateToUse == null) { synchronized (this.delegateMonitor) { - if (this.delegate == null) { + delegateToUse = this.delegate; + if (delegateToUse == null) { WebApplicationContext wac = findWebApplicationContext(); if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: " + "no ContextLoaderListener or DispatcherServlet registered?"); } - this.delegate = initDelegate(wac); + delegateToUse = initDelegate(wac); } - delegateToUse = this.delegate; + this.delegate = delegateToUse; } } @@ -327,7 +332,9 @@ public class DelegatingFilterProxy extends GenericFilterBean { * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ protected Filter initDelegate(WebApplicationContext wac) throws ServletException { - Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); + String targetBeanName = getTargetBeanName(); + Assert.state(targetBeanName != null, "No target bean name set"); + Filter delegate = wac.getBean(targetBeanName, Filter.class); if (isTargetFilterLifecycle()) { delegate.init(getFilterConfig()); } diff --git a/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java b/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java index 3fdc4a3e01..cce050a6cc 100644 --- a/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java +++ b/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java @@ -187,10 +187,12 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { */ private static class ForwardedHeaderExtractingRequest extends ForwardedHeaderRemovingRequest { + @Nullable private final String scheme; private final boolean secure; + @Nullable private final String host; private final int port; @@ -238,11 +240,13 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { } @Override + @Nullable public String getScheme() { return this.scheme; } @Override + @Nullable public String getServerName() { return this.host; } diff --git a/spring-web/src/main/java/org/springframework/web/filter/GenericFilterBean.java b/spring-web/src/main/java/org/springframework/web/filter/GenericFilterBean.java index 922adcf424..c894145475 100644 --- a/spring-web/src/main/java/org/springframework/web/filter/GenericFilterBean.java +++ b/spring-web/src/main/java/org/springframework/web/filter/GenericFilterBean.java @@ -84,12 +84,16 @@ public abstract class GenericFilterBean implements Filter, BeanNameAware, Enviro /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private String beanName; + @Nullable private Environment environment; + @Nullable private ServletContext servletContext; + @Nullable private FilterConfig filterConfig; private final Set requiredProperties = new HashSet<>(4); diff --git a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java index c5e8373b01..1758bb57d8 100644 --- a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java +++ b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java @@ -54,6 +54,7 @@ public class ControllerAdviceBean implements Ordered { private final Object bean; + @Nullable private final BeanFactory beanFactory; private final int order; @@ -137,7 +138,7 @@ public class ControllerAdviceBean implements Ordered { @Nullable public Class getBeanType() { Class beanType = (this.bean instanceof String ? - this.beanFactory.getType((String) this.bean) : this.bean.getClass()); + obtainBeanFactory().getType((String) this.bean) : this.bean.getClass()); return (beanType != null ? ClassUtils.getUserClass(beanType) : null); } @@ -145,7 +146,12 @@ public class ControllerAdviceBean implements Ordered { * Return a bean instance if necessary resolving the bean name through the BeanFactory. */ public Object resolveBean() { - return (this.bean instanceof String ? this.beanFactory.getBean((String) this.bean) : this.bean); + return (this.bean instanceof String ? obtainBeanFactory().getBean((String) this.bean) : this.bean); + } + + private BeanFactory obtainBeanFactory() { + Assert.state(this.beanFactory != null, "No BeanFactory set"); + return this.beanFactory; } /** diff --git a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java index 4b59e59b6d..49a150e849 100644 --- a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java +++ b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java @@ -58,6 +58,7 @@ public class HandlerMethod { private final Object bean; + @Nullable private final BeanFactory beanFactory; private final Class beanType; @@ -118,7 +119,10 @@ public class HandlerMethod { this.bean = beanName; this.beanFactory = beanFactory; Class beanType = beanFactory.getType(beanName); - this.beanType = (beanType != null ? ClassUtils.getUserClass(beanType) : null); + if (beanType == null) { + throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'"); + } + this.beanType = ClassUtils.getUserClass(beanType); this.method = method; this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); this.parameters = initMethodParameters(); @@ -301,6 +305,7 @@ public class HandlerMethod { public HandlerMethod createWithResolvedBean() { Object handler = this.bean; if (this.bean instanceof String) { + Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory"); String beanName = (String) this.bean; handler = this.beanFactory.getBean(beanName); } @@ -380,6 +385,7 @@ public class HandlerMethod { */ private class ReturnValueMethodParameter extends HandlerMethodParameter { + @Nullable private final Object returnValue; public ReturnValueMethodParameter(@Nullable Object returnValue) { diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java index e05ce21474..49ab800167 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java @@ -63,8 +63,10 @@ import org.springframework.web.method.support.ModelAndViewContainer; */ public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver { + @Nullable private final ConfigurableBeanFactory configurableBeanFactory; + @Nullable private final BeanExpressionContext expressionContext; private final Map namedValueInfoCache = new ConcurrentHashMap<>(256); @@ -268,6 +270,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle private final boolean required; + @Nullable private final String defaultValue; public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) { diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java index 569602bbb9..f54f2619d6 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java @@ -22,14 +22,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import org.springframework.core.ExceptionDepthComparator; import org.springframework.core.MethodIntrospector; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; +import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.ReflectionUtils.MethodFilter; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -50,17 +49,10 @@ public class ExceptionHandlerMethodResolver { public static final MethodFilter EXCEPTION_HANDLER_METHODS = method -> (AnnotationUtils.findAnnotation(method, ExceptionHandler.class) != null); - /** - * Arbitrary {@link Method} reference, indicating no method found in the cache. - */ - private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis"); + private final Map, Method> mappedMethods = new ConcurrentReferenceHashMap<>(16); - private final Map, Method> mappedMethods = - new ConcurrentHashMap<>(16); - - private final Map, Method> exceptionLookupCache = - new ConcurrentHashMap<>(16); + private final Map, Method> exceptionLookupCache = new ConcurrentReferenceHashMap<>(16); /** @@ -157,9 +149,9 @@ public class ExceptionHandlerMethodResolver { Method method = this.exceptionLookupCache.get(exceptionType); if (method == null) { method = getMappedMethod(exceptionType); - this.exceptionLookupCache.put(exceptionType, (method != null ? method : NO_METHOD_FOUND)); + this.exceptionLookupCache.put(exceptionType, method); } - return (method != NO_METHOD_FOUND ? method : null); + return method; } /** diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java index 5ae075108c..5e8f409703 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java @@ -102,8 +102,11 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol * @throws Exception if WebDataBinder initialization fails */ @Override - public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { + + Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer"); + Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory"); String name = ModelFactory.getNameForParameter(parameter); Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : diff --git a/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java b/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java index e20210f105..9dd36d74a3 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java @@ -38,8 +38,7 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe protected final Log logger = LogFactory.getLog(getClass()); - private final List returnValueHandlers = - new ArrayList<>(); + private final List returnValueHandlers = new ArrayList<>(); /** @@ -119,7 +118,9 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe /** * Add the given {@link HandlerMethodReturnValueHandler}s. */ - public HandlerMethodReturnValueHandlerComposite addHandlers(@Nullable List handlers) { + public HandlerMethodReturnValueHandlerComposite addHandlers( + @Nullable List handlers) { + if (handlers != null) { for (HandlerMethodReturnValueHandler handler : handlers) { this.returnValueHandlers.add(handler); diff --git a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java index bf6ddc5707..f6f47d704e 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java @@ -48,6 +48,7 @@ import org.springframework.web.method.HandlerMethod; */ public class InvocableHandlerMethod extends HandlerMethod { + @Nullable private WebDataBinderFactory dataBinderFactory; private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite(); diff --git a/spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java b/spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java index ec0470ad90..eecc97f7af 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java @@ -50,10 +50,12 @@ public class ModelAndViewContainer { private boolean ignoreDefaultModelOnRedirect = false; + @Nullable private Object view; private final ModelMap defaultModel = new BindingAwareModelMap(); + @Nullable private ModelMap redirectModel; private boolean redirectModelScenario = false; @@ -61,6 +63,7 @@ public class ModelAndViewContainer { /* Names of attributes with binding disabled */ private final Set bindingDisabledAttributes = new HashSet<>(4); + @Nullable private HttpStatus status; private final SessionStatus sessionStatus = new SimpleSessionStatus(); diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java index 88e09c0a16..e94dca671c 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java @@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequestWrapper; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.multipart.MultipartFile; @@ -42,6 +43,7 @@ import org.springframework.web.multipart.MultipartHttpServletRequest; public abstract class AbstractMultipartHttpServletRequest extends HttpServletRequestWrapper implements MultipartHttpServletRequest { + @Nullable private MultiValueMap multipartFiles; diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java index 5a86c5f5eb..d80945e4bd 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java @@ -46,8 +46,10 @@ public class DefaultMultipartHttpServletRequest extends AbstractMultipartHttpSer private static final String CONTENT_TYPE = "Content-Type"; + @Nullable private Map multipartParameters; + @Nullable private Map multipartParameterContentTypes; diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/RequestPartServletServerHttpRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/RequestPartServletServerHttpRequest.java index bc342977ac..a63ae40898 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/RequestPartServletServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/RequestPartServletServerHttpRequest.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,10 +65,11 @@ public class RequestPartServletServerHttpRequest extends ServletServerHttpReques this.multipartRequest = MultipartResolutionDelegate.asMultipartHttpServletRequest(request); this.partName = partName; - this.headers = this.multipartRequest.getMultipartHeaders(this.partName); - if (this.headers == null) { + HttpHeaders headers = this.multipartRequest.getMultipartHeaders(this.partName); + if (headers == null) { throw new MissingServletRequestPartException(partName); } + this.headers = headers; } @@ -77,7 +78,6 @@ public class RequestPartServletServerHttpRequest extends ServletServerHttpReques return this.headers; } - @Override public InputStream getBody() throws IOException { if (this.multipartRequest instanceof StandardMultipartHttpServletRequest) { diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java index e4e378835a..aed3c95e22 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java @@ -61,6 +61,7 @@ public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpSe private static final String FILENAME_WITH_CHARSET_KEY = "filename*="; + @Nullable private Set multipartParameterNames; diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/StringMultipartFileEditor.java b/spring-web/src/main/java/org/springframework/web/multipart/support/StringMultipartFileEditor.java index 9b6b909283..f068ca9430 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/StringMultipartFileEditor.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/StringMultipartFileEditor.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. @@ -19,6 +19,7 @@ package org.springframework.web.multipart.support; import java.beans.PropertyEditorSupport; import java.io.IOException; +import org.springframework.lang.Nullable; import org.springframework.web.multipart.MultipartFile; /** @@ -32,6 +33,7 @@ import org.springframework.web.multipart.MultipartFile; */ public class StringMultipartFileEditor extends PropertyEditorSupport { + @Nullable private final String charsetName; diff --git a/spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeBuilder.java b/spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeBuilder.java index 3cf224d7d5..61a4ddb46b 100644 --- a/spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/server/DefaultServerWebExchangeBuilder.java @@ -23,6 +23,7 @@ import reactor.core.publisher.Mono; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -35,10 +36,13 @@ class DefaultServerWebExchangeBuilder implements ServerWebExchange.Builder { private final ServerWebExchange delegate; + @Nullable private ServerHttpRequest request; + @Nullable private ServerHttpResponse response; + @Nullable private Mono principalMono; @@ -85,14 +89,17 @@ class DefaultServerWebExchangeBuilder implements ServerWebExchange.Builder { */ private static class MutativeDecorator extends ServerWebExchangeDecorator { + @Nullable private final ServerHttpRequest request; + @Nullable private final ServerHttpResponse response; + @Nullable private final Mono principalMono; - public MutativeDecorator(ServerWebExchange delegate, ServerHttpRequest request, - ServerHttpResponse response, Mono principalMono) { + public MutativeDecorator(ServerWebExchange delegate, @Nullable ServerHttpRequest request, + @Nullable ServerHttpResponse response, @Nullable Mono principalMono) { super(delegate); this.request = request; @@ -113,8 +120,7 @@ class DefaultServerWebExchangeBuilder implements ServerWebExchange.Builder { @SuppressWarnings("unchecked") @Override public Mono getPrincipal() { - return (this.principalMono != null ? - (Mono) this.principalMono : getDelegate().getPrincipal()); + return (this.principalMono != null ? (Mono) this.principalMono : getDelegate().getPrincipal()); } } diff --git a/spring-web/src/main/java/org/springframework/web/server/ResponseStatusException.java b/spring-web/src/main/java/org/springframework/web/server/ResponseStatusException.java index 0bbc5d0e0b..ba77322bc4 100644 --- a/spring-web/src/main/java/org/springframework/web/server/ResponseStatusException.java +++ b/spring-web/src/main/java/org/springframework/web/server/ResponseStatusException.java @@ -34,6 +34,7 @@ public class ResponseStatusException extends NestedRuntimeException { private final HttpStatus status; + @Nullable private final String reason; diff --git a/spring-web/src/main/java/org/springframework/web/server/ServerErrorException.java b/spring-web/src/main/java/org/springframework/web/server/ServerErrorException.java index 95b85d98ae..f25cad1886 100644 --- a/spring-web/src/main/java/org/springframework/web/server/ServerErrorException.java +++ b/spring-web/src/main/java/org/springframework/web/server/ServerErrorException.java @@ -31,6 +31,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ServerErrorException extends ResponseStatusException { + @Nullable private final MethodParameter parameter; diff --git a/spring-web/src/main/java/org/springframework/web/server/ServerWebInputException.java b/spring-web/src/main/java/org/springframework/web/server/ServerWebInputException.java index bc7551a4a0..239704f05a 100644 --- a/spring-web/src/main/java/org/springframework/web/server/ServerWebInputException.java +++ b/spring-web/src/main/java/org/springframework/web/server/ServerWebInputException.java @@ -31,6 +31,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class ServerWebInputException extends ResponseStatusException { + @Nullable private final MethodParameter parameter; diff --git a/spring-web/src/main/java/org/springframework/web/server/UnsupportedMediaTypeStatusException.java b/spring-web/src/main/java/org/springframework/web/server/UnsupportedMediaTypeStatusException.java index 73c04326e8..65067a6232 100644 --- a/spring-web/src/main/java/org/springframework/web/server/UnsupportedMediaTypeStatusException.java +++ b/spring-web/src/main/java/org/springframework/web/server/UnsupportedMediaTypeStatusException.java @@ -32,6 +32,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class UnsupportedMediaTypeStatusException extends ResponseStatusException { + @Nullable private final MediaType contentType; private final List supportedMediaTypes; diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java b/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java index 69103220ed..5be3eadada 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java @@ -30,12 +30,13 @@ import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.web.server.i18n.LocaleContextResolver; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebHandler; import org.springframework.web.server.handler.WebHandlerDecorator; import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver; +import org.springframework.web.server.i18n.LocaleContextResolver; import org.springframework.web.server.session.DefaultWebSessionManager; import org.springframework.web.server.session.WebSessionManager; @@ -83,8 +84,10 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa private WebSessionManager sessionManager = new DefaultWebSessionManager(); + @Nullable private ServerCodecConfigurer codecConfigurer; + @Nullable private LocaleContextResolver localeContextResolver; diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java b/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java index 434b906cc9..a950166973 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.web.server.adapter; import java.util.ArrayList; @@ -27,15 +28,16 @@ import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; -import org.springframework.web.server.i18n.LocaleContextResolver; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebExceptionHandler; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebHandler; import org.springframework.web.server.handler.ExceptionHandlingWebHandler; import org.springframework.web.server.handler.FilteringWebHandler; +import org.springframework.web.server.i18n.LocaleContextResolver; import org.springframework.web.server.session.DefaultWebSessionManager; import org.springframework.web.server.session.WebSessionManager; @@ -81,10 +83,13 @@ public class WebHttpHandlerBuilder { private final List exceptionHandlers = new ArrayList<>(); + @Nullable private WebSessionManager sessionManager; + @Nullable private ServerCodecConfigurer codecConfigurer; + @Nullable private LocaleContextResolver localeContextResolver; diff --git a/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java b/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java index ef9a70f3cb..98deb33de5 100644 --- a/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java +++ b/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java @@ -42,6 +42,7 @@ public class AcceptHeaderLocaleContextResolver implements LocaleContextResolver private final List supportedLocales = new ArrayList<>(4); + @Nullable private Locale defaultLocale; diff --git a/spring-web/src/main/java/org/springframework/web/server/i18n/FixedLocaleContextResolver.java b/spring-web/src/main/java/org/springframework/web/server/i18n/FixedLocaleContextResolver.java index c680915103..1930e9c457 100644 --- a/spring-web/src/main/java/org/springframework/web/server/i18n/FixedLocaleContextResolver.java +++ b/spring-web/src/main/java/org/springframework/web/server/i18n/FixedLocaleContextResolver.java @@ -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. @@ -26,8 +26,8 @@ import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; /** - * {@link LocaleContextResolver} implementation - * that always returns a fixed default locale and optionally time zone. + * {@link LocaleContextResolver} implementation that always returns + * a fixed default locale and optionally time zone. * Default is the current JVM's default locale. * *

Note: Does not support {@code setLocale(Context)}, as the fixed @@ -40,6 +40,7 @@ public class FixedLocaleContextResolver implements LocaleContextResolver { private final Locale locale; + @Nullable private final TimeZone timeZone; diff --git a/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java b/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java index e5e4991a24..3e1700fd1b 100644 --- a/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java +++ b/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java @@ -39,6 +39,7 @@ import org.springframework.util.Assert; @Deprecated public abstract class AbstractUriTemplateHandler implements UriTemplateHandler { + @Nullable private String baseUrl; private final Map defaultUriVariables = new HashMap<>(); diff --git a/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java b/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java index 5c397ea2d3..8fcacc4fac 100644 --- a/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java +++ b/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java @@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; /** * {@link javax.servlet.http.HttpServletRequest} wrapper that caches all content read from @@ -53,10 +54,13 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper { private final ByteArrayOutputStream cachedContent; + @Nullable private final Integer contentCacheLimit; + @Nullable private ServletInputStream inputStream; + @Nullable private BufferedReader reader; diff --git a/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java b/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java index 4a4cc0adfb..33fdc2cd95 100644 --- a/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.java +++ b/spring-web/src/main/java/org/springframework/web/util/ContentCachingResponseWrapper.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. @@ -26,6 +26,7 @@ import javax.servlet.WriteListener; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; +import org.springframework.lang.Nullable; import org.springframework.util.FastByteArrayOutputStream; /** @@ -44,12 +45,15 @@ public class ContentCachingResponseWrapper extends HttpServletResponseWrapper { private final FastByteArrayOutputStream content = new FastByteArrayOutputStream(1024); + @Nullable private ServletOutputStream outputStream; + @Nullable private PrintWriter writer; private int statusCode = HttpServletResponse.SC_OK; + @Nullable private Integer contentLength; diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index edddae68ee..432709b43d 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -54,10 +54,13 @@ final class HierarchicalUriComponents extends UriComponents { private static final String PATH_DELIMITER_STRING = "/"; + @Nullable private final String userInfo; + @Nullable private final String host; + @Nullable private final String port; private final PathComponent path; @@ -107,11 +110,13 @@ final class HierarchicalUriComponents extends UriComponents { } @Override + @Nullable public String getUserInfo() { return this.userInfo; } @Override + @Nullable public String getHost() { return this.host; } @@ -198,8 +203,8 @@ final class HierarchicalUriComponents extends UriComponents { String fragment = getFragment(); String schemeTo = (scheme != null ? encodeUriComponent(scheme, charset, Type.SCHEME) : null); String fragmentTo = (fragment != null ? encodeUriComponent(fragment, charset, Type.FRAGMENT) : null); - String userInfoTo = encodeUriComponent(this.userInfo, charset, Type.USER_INFO); - String hostTo = encodeUriComponent(this.host, charset, getHostType()); + String userInfoTo = (this.userInfo != null ? encodeUriComponent(this.userInfo, charset, Type.USER_INFO) : null); + String hostTo = (this.host != null ? encodeUriComponent(this.host, charset, getHostType()) : null); PathComponent pathTo = this.path.encode(charset); MultiValueMap paramsTo = encodeQueryParams(charset); return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo, hostTo, this.port, @@ -229,7 +234,6 @@ final class HierarchicalUriComponents extends UriComponents { * @return the encoded URI * @throws IllegalArgumentException when the given value is not a valid URI component */ - @Nullable static String encodeUriComponent(String source, String encoding, Type type) { return encodeUriComponent(source, Charset.forName(encoding), type); } diff --git a/spring-web/src/main/java/org/springframework/web/util/OpaqueUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/OpaqueUriComponents.java index b6319346e4..2abf810602 100644 --- a/spring-web/src/main/java/org/springframework/web/util/OpaqueUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/OpaqueUriComponents.java @@ -40,6 +40,7 @@ final class OpaqueUriComponents extends UriComponents { private static final MultiValueMap QUERY_PARAMS_NONE = new LinkedMultiValueMap<>(0); + @Nullable private final String ssp; diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponents.java b/spring-web/src/main/java/org/springframework/web/util/UriComponents.java index 98727b70b3..8e46d11345 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponents.java @@ -50,8 +50,10 @@ public abstract class UriComponents implements Serializable { private static final Pattern NAMES_PATTERN = Pattern.compile("\\{([^/]+?)\\}"); + @Nullable private final String scheme; + @Nullable private final String fragment; diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 658b5e9236..7d4b6d2f6e 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -96,20 +96,26 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { private static final Pattern FORWARDED_PROTO_PATTERN = Pattern.compile("proto=\"?([^;,\"]+)\"?"); + @Nullable private String scheme; + @Nullable private String ssp; + @Nullable private String userInfo; + @Nullable private String host; + @Nullable private String port; private CompositePathComponentBuilder pathBuilder; private final MultiValueMap queryParams = new LinkedMultiValueMap<>(); + @Nullable private String fragment; diff --git a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java index addf9904b3..291f318ad1 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java +++ b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java @@ -56,6 +56,7 @@ public class UrlPathHelper { private static final Log logger = LogFactory.getLog(UrlPathHelper.class); + @Nullable static volatile Boolean websphereComplianceFlag; @@ -568,7 +569,8 @@ public class UrlPathHelper { // Don't remove that slash. return false; } - if (websphereComplianceFlag == null) { + Boolean flagToUse = websphereComplianceFlag; + if (flagToUse == null) { ClassLoader classLoader = UrlPathHelper.class.getClassLoader(); String className = "com.ibm.ws.webcontainer.WebContainer"; String methodName = "getWebContainerProperties"; @@ -584,11 +586,12 @@ public class UrlPathHelper { logger.debug("Could not introspect WebSphere web container properties: " + ex); } } + flagToUse = flag; websphereComplianceFlag = flag; } // Don't bother if WebSphere is configured to be fully Servlet compliant. // However, if it is not compliant, do remove the improper trailing slash! - return !websphereComplianceFlag; + return !flagToUse; } } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java index c439d1fd9d..5fac2e8532 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/CaptureVariablePathElement.java @@ -20,6 +20,7 @@ import java.nio.charset.StandardCharsets; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.springframework.lang.Nullable; import org.springframework.web.util.UriUtils; /** @@ -34,6 +35,7 @@ class CaptureVariablePathElement extends PathElement { private final String variableName; + @Nullable private Pattern constraintPattern; diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java b/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java index 3081de80d5..7622af1506 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.List; import java.util.regex.PatternSyntaxException; +import org.springframework.lang.Nullable; import org.springframework.web.util.UriUtils; import org.springframework.web.util.pattern.PatternParseException.PatternMessage; @@ -45,7 +46,7 @@ class InternalPathPatternParser { private boolean matchOptionalTrailingSlash = false; // The input data for parsing - private char[] pathPatternData; + private char[] pathPatternData = new char[0]; // The length of the input data private int pathPatternLength; @@ -76,12 +77,15 @@ class InternalPathPatternParser { int variableCaptureStart; // Variables captures in this path pattern + @Nullable List capturedVariableNames; // The head of the path element chain currently being built + @Nullable PathElement headPE; // The most recently constructed path element in the chain + @Nullable PathElement currentPE; @@ -297,7 +301,7 @@ class InternalPathPatternParser { this.headPE = newPathElement; this.currentPE = newPathElement; } - else { + else if (this.currentPE != null) { this.currentPE.next = newPathElement; newPathElement.prev = this.currentPE; this.currentPE = newPathElement; diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java index dc65ce7478..bd23ec5756 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java @@ -18,6 +18,7 @@ package org.springframework.web.util.pattern; import java.nio.charset.StandardCharsets; +import org.springframework.lang.Nullable; import org.springframework.web.util.UriUtils; import org.springframework.web.util.pattern.PathPattern.MatchingContext; @@ -42,9 +43,11 @@ abstract class PathElement { protected final char separator; // The next path element in the chain + @Nullable protected PathElement next; // The previous path element in the chain + @Nullable protected PathElement prev; diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java index 671e580b40..94d74b1d7c 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java @@ -64,6 +64,7 @@ import org.springframework.util.StringUtils; public class PathPattern implements Comparable { /** First path element in the parsed chain of path elements for this pattern */ + @Nullable private PathElement head; /** The text of the parsed pattern */ @@ -142,6 +143,7 @@ public class PathPattern implements Comparable { return this.patternString; } + @Nullable PathElement getHeadSection() { return this.head; } @@ -550,6 +552,7 @@ public class PathPattern implements Comparable { boolean isMatchStartMatching = false; + @Nullable private Map extractedVariables; boolean extractingVariables; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java b/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java index e3d76f1c38..35ebd661d0 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java @@ -37,6 +37,7 @@ import org.springframework.web.server.ServerWebExchange; */ public class BindingContext { + @Nullable private final WebBindingInitializer initializer; private final Model model = new BindingAwareConcurrentModel(); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/HandlerResult.java b/spring-webflux/src/main/java/org/springframework/web/reactive/HandlerResult.java index 89118242e9..d2e5130a38 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/HandlerResult.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/HandlerResult.java @@ -36,12 +36,14 @@ public class HandlerResult { private final Object handler; + @Nullable private final Object returnValue; private final ResolvableType returnType; private final BindingContext bindingContext; + @Nullable private Function> exceptionHandler; @@ -144,7 +146,7 @@ public class HandlerResult { * @return the new result or the same error if there is no exception handler */ public Mono applyExceptionHandler(Throwable failure) { - return (hasExceptionHandler() ? this.exceptionHandler.apply(failure) : Mono.error(failure)); + return (this.exceptionHandler != null ? this.exceptionHandler.apply(failure) : Mono.error(failure)); } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java index 5a88cc4a97..3d40e84de7 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.web.reactive.accept; import java.util.ArrayList; @@ -25,7 +26,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import org.springframework.http.MediaType; - +import org.springframework.lang.Nullable; /** * Builder for a composite {@link RequestedContentTypeResolver} that delegates @@ -113,9 +114,9 @@ public class RequestedContentTypeResolverBuilder { private final Map mediaTypes = new HashMap<>(); + @Nullable private String parameterName; - /** * Configure a mapping between a lookup key (extracted from a query * parameter value) and a corresponding {@code MediaType}. diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistration.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistration.java index 6182b21dce..37ee84058d 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistration.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistration.java @@ -23,6 +23,7 @@ import org.springframework.cache.Cache; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.http.CacheControl; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.resource.ResourceWebHandler; @@ -40,8 +41,10 @@ public class ResourceHandlerRegistration { private final List locations = new ArrayList<>(); + @Nullable private CacheControl cacheControl; + @Nullable private ResourceChainRegistration resourceChainRegistration; @@ -52,7 +55,8 @@ public class ResourceHandlerRegistration { * @param pathPatterns one or more resource URL path patterns */ public ResourceHandlerRegistration(ResourceLoader resourceLoader, String... pathPatterns) { - Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling."); + Assert.notNull(resourceLoader, "ResourceLoader is required"); + Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling"); this.resourceLoader = resourceLoader; this.pathPatterns = pathPatterns; } @@ -74,7 +78,7 @@ public class ResourceHandlerRegistration { */ public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) { for (String location : resourceLocations) { - this.locations.add(resourceLoader.getResource(location)); + this.locations.add(this.resourceLoader.getResource(location)); } return this; } @@ -82,7 +86,6 @@ public class ResourceHandlerRegistration { /** * Specify the {@link CacheControl} which should be used * by the resource handler. - * * @param cacheControl the CacheControl configuration to use * @return the same {@link ResourceHandlerRegistration} instance, for * chained method invocation @@ -95,11 +98,9 @@ public class ResourceHandlerRegistration { /** * Configure a chain of resource resolvers and transformers to use. This * can be useful, for example, to apply a version strategy to resource URLs. - * *

If this method is not invoked, by default only a simple * {@code PathResourceResolver} is used in order to match URL paths to * resources under the configured locations. - * * @param cacheResources whether to cache the result of resource resolution; * setting this to "true" is recommended for production (and "false" for * development, especially when applying a version strategy) @@ -114,11 +115,9 @@ public class ResourceHandlerRegistration { /** * Configure a chain of resource resolvers and transformers to use. This * can be useful, for example, to apply a version strategy to resource URLs. - * *

If this method is not invoked, by default only a simple * {@code PathResourceResolver} is used in order to match URL paths to * resources under the configured locations. - * * @param cacheResources whether to cache the result of resource resolution; * setting this to "true" is recommended for production (and "false" for * development, especially when applying a version strategy diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java index d58c8a60b2..3ca0bb3bdf 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java @@ -23,9 +23,8 @@ import java.util.List; import java.util.Map; import org.springframework.beans.factory.BeanInitializationException; -import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ResourceLoader; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; import org.springframework.web.reactive.handler.AbstractUrlHandlerMapping; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; import org.springframework.web.reactive.resource.ResourceWebHandler; @@ -53,7 +52,7 @@ import org.springframework.web.server.WebHandler; */ public class ResourceHandlerRegistry { - private final ApplicationContext applicationContext; + private final ResourceLoader resourceLoader; private final List registrations = new ArrayList<>(); @@ -61,13 +60,12 @@ public class ResourceHandlerRegistry { /** - * Create a new resource handler registry for the given application context. - * @param applicationContext the Spring application context + * Create a new resource handler registry for the given resource loader + * (typically an application context). + * @param resourceLoader the resource loader to use */ - public ResourceHandlerRegistry(ApplicationContext applicationContext) { - - Assert.notNull(applicationContext, "ApplicationContext is required"); - this.applicationContext = applicationContext; + public ResourceHandlerRegistry(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; } @@ -82,8 +80,7 @@ public class ResourceHandlerRegistry { * configure the registered resource handler */ public ResourceHandlerRegistration addResourceHandler(String... patterns) { - ResourceHandlerRegistration registration = - new ResourceHandlerRegistration(this.applicationContext, patterns); + ResourceHandlerRegistration registration = new ResourceHandlerRegistration(this.resourceLoader, patterns); this.registrations.add(registration); return registration; } @@ -126,7 +123,7 @@ public class ResourceHandlerRegistry { try { handler.afterPropertiesSet(); } - catch (Exception ex) { + catch (Throwable ex) { throw new BeanInitializationException("Failed to init ResourceHttpRequestHandler", ex); } urlMap.put(pathPattern, handler); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ViewResolverRegistry.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ViewResolverRegistry.java index 877079c65d..8c187d518f 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ViewResolverRegistry.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ViewResolverRegistry.java @@ -24,7 +24,7 @@ import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.context.ApplicationContext; import org.springframework.core.Ordered; -import org.springframework.util.Assert; +import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.web.reactive.result.view.HttpMessageWriterView; import org.springframework.web.reactive.result.view.UrlBasedViewResolver; @@ -46,17 +46,18 @@ import org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewRes */ public class ViewResolverRegistry { + @Nullable private final ApplicationContext applicationContext; private final List viewResolvers = new ArrayList<>(4); private final List defaultViews = new ArrayList<>(4); + @Nullable private Integer order; - public ViewResolverRegistry(ApplicationContext applicationContext) { - Assert.notNull(applicationContext, "ApplicationContext must not be null"); + public ViewResolverRegistry(@Nullable ApplicationContext applicationContext) { this.applicationContext = applicationContext; } @@ -67,7 +68,7 @@ public class ViewResolverRegistry { * adding a {@link FreeMarkerConfigurer} bean. */ public UrlBasedViewResolverRegistration freeMarker() { - if (this.applicationContext != null && !hasBeanOfType(FreeMarkerConfigurer.class)) { + if (!checkBeanOfType(FreeMarkerConfigurer.class)) { throw new BeanInitializationException("In addition to a FreeMarker view resolver " + "there must also be a single FreeMarkerConfig bean in this web application context " + "(or its parent): FreeMarkerConfigurer is the usual implementation. " + @@ -82,11 +83,6 @@ public class ViewResolverRegistry { return registration; } - protected boolean hasBeanOfType(Class beanType) { - return !ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors( - this.applicationContext, beanType, false, false)); - } - /** * Register a {@link ViewResolver} bean instance. This may be useful to * configure a 3rd party resolver implementation or as an alternative to @@ -126,6 +122,13 @@ public class ViewResolverRegistry { this.order = order; } + + private boolean checkBeanOfType(Class beanType) { + return (this.applicationContext == null || + !ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors( + this.applicationContext, beanType, false, false))); + } + protected int getOrder() { return (this.order != null ? this.order : Ordered.LOWEST_PRECEDENCE); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java index 8c0a510cac..5589acff09 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java @@ -29,6 +29,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.annotation.Order; import org.springframework.core.convert.converter.Converter; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; import org.springframework.format.support.DefaultFormattingConversionService; @@ -58,11 +60,11 @@ import org.springframework.web.reactive.result.method.annotation.ResponseBodyRes import org.springframework.web.reactive.result.method.annotation.ResponseEntityResultHandler; import org.springframework.web.reactive.result.view.ViewResolutionResultHandler; import org.springframework.web.reactive.result.view.ViewResolver; -import org.springframework.web.server.i18n.LocaleContextResolver; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebExceptionHandler; import org.springframework.web.server.handler.ResponseStatusExceptionHandler; import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver; +import org.springframework.web.server.i18n.LocaleContextResolver; /** * The main class for Spring WebFlux configuration. @@ -74,12 +76,16 @@ import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver; */ public class WebFluxConfigurationSupport implements ApplicationContextAware { + @Nullable private Map corsConfigurations; + @Nullable private PathMatchConfigurer pathMatchConfigurer; + @Nullable private ViewResolverRegistry viewResolverRegistry; + @Nullable private ApplicationContext applicationContext; @@ -88,7 +94,8 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { this.applicationContext = applicationContext; } - protected ApplicationContext getApplicationContext() { + @Nullable + public final ApplicationContext getApplicationContext() { return this.applicationContext; } @@ -205,7 +212,11 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { */ @Bean public HandlerMapping resourceHandlerMapping() { - ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext); + ResourceLoader resourceLoader = this.applicationContext; + if (resourceLoader == null) { + resourceLoader = new DefaultResourceLoader(); + } + ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader); addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); @@ -427,7 +438,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { */ protected final ViewResolverRegistry getViewResolverRegistry() { if (this.viewResolverRegistry == null) { - this.viewResolverRegistry = new ViewResolverRegistry(getApplicationContext()); + this.viewResolverRegistry = new ViewResolverRegistry(this.applicationContext); configureViewResolvers(this.viewResolverRegistry); } return this.viewResolverRegistry; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/UnsupportedMediaTypeException.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/UnsupportedMediaTypeException.java index 891e2120e0..ecbe5c222d 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/UnsupportedMediaTypeException.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/UnsupportedMediaTypeException.java @@ -32,6 +32,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class UnsupportedMediaTypeException extends NestedRuntimeException { + @Nullable private final MediaType contentType; private final List supportedMediaTypes; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java index c1ba022d64..c7b77b8cf5 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java @@ -63,8 +63,10 @@ class DefaultWebClient implements WebClient { private final UriBuilderFactory uriBuilderFactory; + @Nullable private final HttpHeaders defaultHeaders; + @Nullable private final MultiValueMap defaultCookies; private final DefaultWebClientBuilder builder; @@ -170,10 +172,13 @@ class DefaultWebClient implements WebClient { private final URI uri; + @Nullable private HttpHeaders headers; + @Nullable private MultiValueMap cookies; + @Nullable private BodyInserter inserter; DefaultRequestBodySpec(HttpMethod httpMethod, URI uri) { @@ -284,11 +289,9 @@ class DefaultWebClient implements WebClient { @Override public Mono exchange() { - - ClientRequest request = this.inserter != null ? + ClientRequest request = (this.inserter != null ? initRequestBuilder().body(this.inserter).build() : - initRequestBuilder().build(); - + initRequestBuilder().build()); return exchangeFunction.exchange(request); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java index 34dce879f2..fdcac231ea 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java @@ -42,24 +42,33 @@ import org.springframework.web.util.UriBuilderFactory; */ class DefaultWebClientBuilder implements WebClient.Builder { + @Nullable private String baseUrl; + @Nullable private Map defaultUriVariables; + @Nullable private UriBuilderFactory uriBuilderFactory; + @Nullable private HttpHeaders defaultHeaders; + @Nullable private MultiValueMap defaultCookies; + @Nullable private List filters; + @Nullable private ClientHttpConnector connector; private ExchangeStrategies exchangeStrategies = ExchangeStrategies.withDefaults(); + @Nullable private ExchangeFunction exchangeFunction; + public DefaultWebClientBuilder() { } @@ -85,6 +94,7 @@ class DefaultWebClientBuilder implements WebClient.Builder { this.exchangeFunction = other.exchangeFunction; } + @Override public WebClient.Builder baseUrl(String baseUrl) { this.baseUrl = baseUrl; @@ -105,9 +115,9 @@ class DefaultWebClientBuilder implements WebClient.Builder { @Override public WebClient.Builder defaultHeader(String headerName, String... headerValues) { - initHeaders(); + HttpHeaders headers = initHeaders(); for (String headerValue : headerValues) { - this.defaultHeaders.add(headerName, headerValue); + headers.add(headerName, headerValue); } return this; } @@ -115,37 +125,35 @@ class DefaultWebClientBuilder implements WebClient.Builder { @Override public WebClient.Builder defaultHeaders(Consumer headersConsumer) { Assert.notNull(headersConsumer, "'headersConsumer' must not be null"); - initHeaders(); - headersConsumer.accept(this.defaultHeaders); + headersConsumer.accept(initHeaders()); return this; } - private void initHeaders() { + private HttpHeaders initHeaders() { if (this.defaultHeaders == null) { this.defaultHeaders = new HttpHeaders(); } + return this.defaultHeaders; } @Override public WebClient.Builder defaultCookie(String cookieName, String... cookieValues) { - initCookies(); - this.defaultCookies.addAll(cookieName, Arrays.asList(cookieValues)); + initCookies().addAll(cookieName, Arrays.asList(cookieValues)); return this; } @Override - public WebClient.Builder defaultCookies( - Consumer> cookiesConsumer) { - Assert.notNull(cookiesConsumer, "'cookiesConsumer' must not be null"); - initCookies(); - cookiesConsumer.accept(this.defaultCookies); + public WebClient.Builder defaultCookies(Consumer> cookiesConsumer) { + Assert.notNull(cookiesConsumer, "Cookies consumer must not be null"); + cookiesConsumer.accept(initCookies()); return this; } - private void initCookies() { + private MultiValueMap initCookies() { if (this.defaultCookies == null) { this.defaultCookies = new LinkedMultiValueMap<>(4); } + return this.defaultCookies; } @Override @@ -156,29 +164,28 @@ class DefaultWebClientBuilder implements WebClient.Builder { @Override public WebClient.Builder filter(ExchangeFilterFunction filter) { - Assert.notNull(filter, "'filter' must not be null"); - initFilters(); - this.filters.add(filter); + Assert.notNull(filter, "ExchangeFilterFunction must not be null"); + initFilters().add(filter); return this; } @Override public WebClient.Builder filters(Consumer> filtersConsumer) { - Assert.notNull(filtersConsumer, "'filtersConsumer' must not be null"); - initFilters(); - filtersConsumer.accept(this.filters); + Assert.notNull(filtersConsumer, "Filters consumer must not be null"); + filtersConsumer.accept(initFilters()); return this; } - private void initFilters() { + private List initFilters() { if (this.filters == null) { this.filters = new ArrayList<>(); } + return this.filters; } @Override public WebClient.Builder exchangeStrategies(ExchangeStrategies strategies) { - Assert.notNull(strategies, "'strategies' must not be null"); + Assert.notNull(strategies, "ExchangeStrategies must not be null"); this.exchangeStrategies = strategies; return this; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java index d4152faf72..a340d2c57a 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java @@ -392,6 +392,7 @@ public interface ServerResponse { Mono render(String name, Map model); } + /** * Defines the context used during the {@link #writeTo(ServerWebExchange, Context)}. */ @@ -399,13 +400,13 @@ public interface ServerResponse { /** * Return the {@link HttpMessageWriter}s to be used for response body conversion. - * @return the stream of message writers + * @return the list of message writers */ List> messageWriters(); /** * Return the {@link ViewResolver}s to be used for view name resolution. - * @return the stream of view resolvers + * @return the list of view resolvers */ List viewResolvers(); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java index d5edaa24fd..d799884000 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java @@ -24,6 +24,8 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; @@ -43,10 +45,13 @@ import org.springframework.web.server.ServerWebExchange; */ public class RouterFunctionMapping extends AbstractHandlerMapping implements InitializingBean { + @Nullable private RouterFunction routerFunction; + @Nullable private ServerCodecConfigurer messageCodecConfigurer; + /** * Create an empty {@code RouterFunctionMapping}. *

If this constructor is used, this mapping will detect all {@link RouterFunction} instances @@ -64,6 +69,7 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini this.routerFunction = routerFunction; } + /** * Configure HTTP message readers to de-serialize the request body with. *

By default this is set to {@link ServerCodecConfigurer} with defaults. @@ -114,6 +120,7 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini @Override protected Mono getHandlerInternal(ServerWebExchange exchange) { if (this.routerFunction != null) { + Assert.state(this.messageCodecConfigurer != null, "No ServerCodecConfigurer set"); ServerRequest request = ServerRequest.create(exchange, this.messageCodecConfigurer.getReaders()); exchange.getAttributes().put(RouterFunctions.REQUEST_ATTRIBUTE, request); return this.routerFunction.route(request); @@ -123,8 +130,10 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini } } + private static class SortedRouterFunctionsContainer { + @Nullable private List> routerFunctions; @Autowired(required = false) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java index a0a28443cb..d0c1aa4002 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.core.Ordered; import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.HandlerResult; import org.springframework.web.reactive.HandlerResultHandler; @@ -38,12 +39,12 @@ import org.springframework.web.server.ServerWebExchange; * @author Arjen Poutsma * @since 5.0 */ -public class ServerResponseResultHandler implements HandlerResultHandler, InitializingBean, - Ordered { +public class ServerResponseResultHandler implements HandlerResultHandler, InitializingBean, Ordered { + @Nullable private ServerCodecConfigurer messageCodecConfigurer; - private List viewResolvers; + private List viewResolvers = Collections.emptyList(); private int order = LOWEST_PRECEDENCE; @@ -79,10 +80,7 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia @Override public void afterPropertiesSet() throws Exception { if (this.messageCodecConfigurer == null) { - throw new IllegalArgumentException("'messageCodecConfigurer' is required"); - } - if (this.viewResolvers == null) { - this.viewResolvers = Collections.emptyList(); + throw new IllegalArgumentException("Property 'messageCodecConfigurer' is required"); } } @@ -98,9 +96,9 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia return response.writeTo(exchange, new ServerResponse.Context() { @Override public List> messageWriters() { - return messageCodecConfigurer.getWriters(); + return (messageCodecConfigurer != null ? + messageCodecConfigurer.getWriters() : Collections.emptyList()); } - @Override public List viewResolvers() { return viewResolvers; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java index dabb19812c..5dedc9d240 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java @@ -16,6 +16,7 @@ package org.springframework.web.reactive.handler; +import java.util.Collections; import java.util.Map; import java.util.Optional; @@ -50,11 +51,9 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { private boolean lazyInitHandlers = false; + @Nullable private PathPatternRegistry patternRegistry; - public PathPatternRegistry getPatternRegistry() { - return patternRegistry; - } /** * Set whether to lazily initialize handlers. Only applicable to @@ -76,7 +75,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { * as value. */ public final Map getHandlerMap() { - return this.patternRegistry.getPatternsMap(); + return (this.patternRegistry != null ? this.patternRegistry.getPatternsMap() : Collections.emptyMap()); } @@ -103,11 +102,9 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { /** * Look up a handler instance for the given URL lookup path. - * *

Supports direct matches, e.g. a registered "/test" matches "/test", * and various path pattern matches, e.g. a registered "/t*" matches * both "/test" and "/team". For details, see the PathPattern class. - * * @param lookupPath URL the handler is mapped to * @param exchange the current exchange * @return the associated handler instance, or {@code null} if not found @@ -115,19 +112,17 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { */ @Nullable protected Object lookupHandler(String lookupPath, ServerWebExchange exchange) throws Exception { - Optional> matches = this.patternRegistry.findFirstMatch(lookupPath); - if (matches.isPresent()) { - if (logger.isDebugEnabled()) { - logger.debug("Matching patterns for request [" + lookupPath + "] are " + matches); + if (this.patternRegistry != null) { + Optional> matches = this.patternRegistry.findFirstMatch(lookupPath); + if (matches.isPresent()) { + if (logger.isDebugEnabled()) { + logger.debug("Matching patterns for request [" + lookupPath + "] are " + matches); + } + PathMatchResult bestMatch = matches.get(); + String pathWithinMapping = bestMatch.getPattern().extractPathWithinPattern(lookupPath); + Object handler = bestMatch.getHandler(); + return handleMatch(handler, bestMatch.getPattern(), pathWithinMapping, exchange); } - PathMatchResult bestMatch = matches.get(); - String pathWithinMapping = bestMatch.getPattern().extractPathWithinPattern(lookupPath); - Object handler = bestMatch.getHandler(); - if (handler == null) { - throw new IllegalStateException( - "Could not find handler for best pattern match [" + bestMatch + "]"); - } - return handleMatch(handler, bestMatch.getPattern(), pathWithinMapping, exchange); } // No handler found... diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/PathMatchResult.java b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/PathMatchResult.java index ee07aa5a39..7fc98e64bd 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/PathMatchResult.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/PathMatchResult.java @@ -16,7 +16,6 @@ package org.springframework.web.reactive.handler; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.util.pattern.PathPattern; @@ -37,8 +36,9 @@ public class PathMatchResult { private final T handler; - public PathMatchResult(PathPattern pattern, @Nullable T handler) { + public PathMatchResult(PathPattern pattern, T handler) { Assert.notNull(pattern, "PathPattern must not be null"); + Assert.notNull(handler, "Handler must not be null"); this.pattern = pattern; this.handler = handler; } @@ -54,7 +54,6 @@ public class PathMatchResult { /** * Return the request handler associated with the {@link PathPattern}. */ - @Nullable public T getHandler() { return this.handler; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/AppCacheManifestTransformer.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/AppCacheManifestTransformer.java index 3e2890050a..f6cc367f16 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/AppCacheManifestTransformer.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/AppCacheManifestTransformer.java @@ -164,14 +164,13 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { private final Scanner scanner; + @Nullable private LineInfo previous; - public LineGenerator(String content) { this.scanner = new Scanner(content); } - @Override public void accept(SynchronousSink sink) { if (this.scanner.hasNext()) { @@ -186,6 +185,7 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { } } + private static class LineInfo { private final String line; @@ -194,8 +194,7 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { private final boolean link; - - public LineInfo(String line, LineInfo previousLine) { + public LineInfo(String line, @Nullable LineInfo previousLine) { this.line = line; this.cacheSection = initCacheSectionFlag(line, previousLine); this.link = iniLinkFlag(line, this.cacheSection); @@ -222,7 +221,6 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { return (line.startsWith("//") || (index > 0 && !line.substring(0, index).contains("/"))); } - public String getLine() { return this.line; } @@ -236,13 +234,14 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { } } + private static class LineOutput { private final String line; + @Nullable private final Resource resource; - public LineOutput(String line, @Nullable Resource resource) { this.line = line; this.resource = resource; @@ -258,6 +257,7 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { } } + private static class LineAggregator { private final StringWriter writer = new StringWriter(); @@ -266,7 +266,6 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { private final Resource resource; - public LineAggregator(Resource resource, String content) { this.resource = resource; this.baos = new ByteArrayOutputStream(content.length()); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java index d19b8012d2..2090af065a 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceUrlProvider.java @@ -205,9 +205,6 @@ public class ResourceUrlProvider implements ApplicationListener { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/TransformedResource.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/TransformedResource.java index a5c7ac9d21..7557244ff0 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/TransformedResource.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/TransformedResource.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,17 +20,19 @@ import java.io.IOException; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; /** - * An extension of {@link ByteArrayResource} - * that a {@link ResourceTransformer} can use to represent an original - * resource preserving all other information except the content. + * An extension of {@link ByteArrayResource} that a {@link ResourceTransformer} + * can use to represent an original resource preserving all other information + * except the content. * * @author Rossen Stoyanchev * @since 5.0 */ public class TransformedResource extends ByteArrayResource { + @Nullable private final String filename; private final long lastModified; @@ -50,6 +52,7 @@ public class TransformedResource extends ByteArrayResource { @Override + @Nullable public String getFilename() { return this.filename; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java index 71de03b2a0..da1fc5df62 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java @@ -48,6 +48,7 @@ import org.springframework.web.util.pattern.PathPatternParser; */ public final class RequestMappingInfo implements RequestCondition { + @Nullable private final String name; private final PatternsRequestCondition patternsCondition; @@ -392,18 +393,25 @@ public final class RequestMappingInfo implements RequestCondition customCondition; private BuilderConfiguration options = new BuilderConfiguration(); @@ -492,19 +500,21 @@ public final class RequestMappingInfo implements RequestConditionBy default this is not set. diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java index f7365d363f..fe6057cf03 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.lang.Nullable; import org.springframework.web.method.HandlerMethod; import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.HandlerResult; @@ -93,6 +94,7 @@ public class SyncInvocableHandlerMethod extends HandlerMethod { * @param providedArgs optional list of argument values to match by type * @return Mono with a {@link HandlerResult}. */ + @Nullable public HandlerResult invokeForHandlerResult(ServerWebExchange exchange, BindingContext bindingContext, Object... providedArgs) { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java index 36b645ba75..d50a3b6208 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java @@ -60,8 +60,10 @@ import org.springframework.web.server.ServerWebInputException; */ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodArgumentResolverSupport { + @Nullable private final ConfigurableBeanFactory configurableBeanFactory; + @Nullable private final BeanExpressionContext expressionContext; private final Map namedValueInfoCache = new ConcurrentHashMap<>(256); @@ -154,7 +156,7 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr */ @Nullable private Object resolveStringValue(String value) { - if (this.configurableBeanFactory == null) { + if (this.configurableBeanFactory == null || this.expressionContext == null) { return value; } String placeholdersResolved = this.configurableBeanFactory.resolveEmbeddedValue(value); @@ -291,6 +293,7 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr private final boolean required; + @Nullable private final String defaultValue; public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java index 3c9c978366..f99c963745 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java @@ -52,7 +52,7 @@ import org.springframework.web.reactive.result.method.InvocableHandlerMethod; import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod; -import static org.springframework.core.MethodIntrospector.selectMethods; +import static org.springframework.core.MethodIntrospector.*; /** * Package-private class to assist {@link RequestMappingHandlerAdapter} with @@ -218,7 +218,6 @@ class ControllerMethodResolver { * or in the controller of the given {@code @RequestMapping} method. */ public List getInitBinderMethods(HandlerMethod handlerMethod) { - List result = new ArrayList<>(); Class handlerType = handlerMethod.getBeanType(); @@ -251,7 +250,6 @@ class ControllerMethodResolver { * components or in the controller of the given {@code @RequestMapping} method. */ public List getModelAttributeMethods(HandlerMethod handlerMethod) { - List result = new ArrayList<>(); Class handlerType = handlerMethod.getBeanType(); @@ -331,18 +329,18 @@ class ControllerMethodResolver { private final List customResolvers; + @Nullable private final List> messageReaders; private final boolean modelAttributeSupported; private final List result = new ArrayList<>(); - private ArgumentResolverRegistrar(ArgumentResolverConfigurer resolvers, @Nullable ServerCodecConfigurer codecs, boolean modelAttribute) { this.customResolvers = resolvers.getCustomResolvers(); - this.messageReaders = codecs != null ? codecs.getReaders() : null; + this.messageReaders = (codecs != null ? codecs.getReaders() : null); this.modelAttributeSupported = modelAttribute; } @@ -379,7 +377,6 @@ class ControllerMethodResolver { .collect(Collectors.toList()); } - public static Builder configurer(ArgumentResolverConfigurer configurer) { return new Builder(configurer); } @@ -389,12 +386,10 @@ class ControllerMethodResolver { private final ArgumentResolverConfigurer resolvers; - public Builder(ArgumentResolverConfigurer configurer) { this.resolvers = configurer; } - public ArgumentResolverRegistrar fullSupport(ServerCodecConfigurer codecs) { return new ArgumentResolverRegistrar(this.resolvers, codecs, true); } @@ -407,7 +402,6 @@ class ControllerMethodResolver { return new ArgumentResolverRegistrar(this.resolvers, null, false); } } - } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java index ca2f9d9020..54c5c716d5 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContext.java @@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.bind.support.WebExchangeDataBinder; import org.springframework.web.reactive.BindingContext; +import org.springframework.web.reactive.HandlerResult; import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod; import org.springframework.web.server.ServerWebExchange; @@ -71,10 +72,10 @@ class InitBinderBindingContext extends BindingContext { private void invokeBinderMethod(WebExchangeDataBinder dataBinder, ServerWebExchange exchange, SyncInvocableHandlerMethod binderMethod) { - Object returnValue = binderMethod.invokeForHandlerResult(exchange, this.binderMethodContext, dataBinder) - .getReturnValue(); + HandlerResult result = binderMethod.invokeForHandlerResult( + exchange, this.binderMethodContext, dataBinder); - if (returnValue != null) { + if (result != null && result.getReturnValue() != null) { throw new IllegalStateException( "@InitBinder methods should return void: " + binderMethod); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java index 2def9f1a6a..20659708ca 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java @@ -50,18 +50,25 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application private static final Log logger = LogFactory.getLog(RequestMappingHandlerAdapter.class); + @Nullable private ServerCodecConfigurer messageCodecConfigurer; + @Nullable private WebBindingInitializer webBindingInitializer; + @Nullable private ArgumentResolverConfigurer argumentResolverConfigurer; + @Nullable private ReactiveAdapterRegistry reactiveAdapterRegistry; + @Nullable private ConfigurableApplicationContext applicationContext; + @Nullable private ControllerMethodResolver methodResolver; + @Nullable private ModelInitializer modelInitializer; @@ -76,6 +83,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application /** * Return the configurer for HTTP message readers. */ + @Nullable public ServerCodecConfigurer getMessageCodecConfigurer() { return this.messageCodecConfigurer; } @@ -107,6 +115,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application /** * Return the configured resolvers for controller method arguments. */ + @Nullable public ArgumentResolverConfigurer getArgumentResolverConfigurer() { return this.argumentResolverConfigurer; } @@ -123,6 +132,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application /** * Return the configured registry for adapting reactive types. */ + @Nullable public ReactiveAdapterRegistry getReactiveAdapterRegistry() { return this.reactiveAdapterRegistry; } @@ -139,22 +149,17 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application } } - public ConfigurableApplicationContext getApplicationContext() { - return this.applicationContext; - } - @Override public void afterPropertiesSet() throws Exception { + Assert.notNull(this.applicationContext, "ApplicationContext is required"); if (this.messageCodecConfigurer == null) { this.messageCodecConfigurer = ServerCodecConfigurer.create(); } - if (this.argumentResolverConfigurer == null) { this.argumentResolverConfigurer = new ArgumentResolverConfigurer(); } - if (this.reactiveAdapterRegistry == null) { this.reactiveAdapterRegistry = new ReactiveAdapterRegistry(); } @@ -173,9 +178,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @Override public Mono handle(ServerWebExchange exchange, Object handler) { - - Assert.notNull(handler, "Expected handler"); HandlerMethod handlerMethod = (HandlerMethod) handler; + Assert.state(this.methodResolver != null && this.modelInitializer != null, "Not initialized"); BindingContext bindingContext = new InitBinderBindingContext( getWebBindingInitializer(), this.methodResolver.getInitBinderMethods(handlerMethod)); @@ -197,6 +201,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application private Mono handleException(Throwable ex, HandlerMethod handlerMethod, BindingContext bindingContext, ServerWebExchange exchange) { + Assert.state(this.methodResolver != null, "Not initialized"); + InvocableHandlerMethod invocable = this.methodResolver.getExceptionHandlerMethod(ex, handlerMethod); if (invocable != null) { try { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java index f71eb3c3fa..6777ee7ce7 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java @@ -50,6 +50,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi private RequestedContentTypeResolver contentTypeResolver = new RequestedContentTypeResolverBuilder().build(); + @Nullable private StringValueResolver embeddedValueResolver; private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration(); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java index 30e470101c..6ceafbdff3 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java @@ -62,8 +62,10 @@ public abstract class AbstractView implements View, ApplicationContextAware { private Charset defaultCharset = StandardCharsets.UTF_8; + @Nullable private String requestContextAttribute; + @Nullable private ApplicationContext applicationContext; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/BindStatus.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/BindStatus.java index 250d1ec8ca..5ff4e696b6 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/BindStatus.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/BindStatus.java @@ -24,6 +24,7 @@ import org.springframework.beans.BeanWrapper; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.context.NoSuchMessageException; import org.springframework.lang.Nullable; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; @@ -51,25 +52,34 @@ public class BindStatus { private final boolean htmlEscape; + @Nullable private final String expression; + @Nullable private final Errors errors; + @Nullable private BindingResult bindingResult; + @Nullable private Object value; + @Nullable private Class valueType; + @Nullable private Object actualValue; + @Nullable private PropertyEditor editor; + @Nullable private List objectErrors; - private String[] errorCodes; + private String[] errorCodes = new String[0]; + @Nullable private String[] errorMessages; @@ -244,14 +254,13 @@ public class BindStatus { * Return if this status represents a field or object error. */ public boolean isError() { - return (this.errorCodes != null && this.errorCodes.length > 0); + return (this.errorCodes.length > 0); } /** * Return the error codes for the field or object, if any. * Returns an empty array instead of null if none. */ - @Nullable public String[] getErrorCodes() { return this.errorCodes; } @@ -260,7 +269,7 @@ public class BindStatus { * Return the first error codes for the field or object, if any. */ public String getErrorCode() { - return (this.errorCodes.length > 0 ? this.errorCodes[0] : ""); + return (!ObjectUtils.isEmpty(this.errorCodes) ? this.errorCodes[0] : ""); } /** @@ -268,16 +277,15 @@ public class BindStatus { * if any. Returns an empty array instead of null if none. */ public String[] getErrorMessages() { - initErrorMessages(); - return this.errorMessages; + return initErrorMessages(); } /** * Return the first error message for the field or object, if any. */ public String getErrorMessage() { - initErrorMessages(); - return (this.errorMessages.length > 0 ? this.errorMessages[0] : ""); + String[] errorMessages = initErrorMessages(); + return (errorMessages.length > 0 ? errorMessages[0] : ""); } /** @@ -287,21 +295,26 @@ public class BindStatus { * @return the error message string */ public String getErrorMessagesAsString(String delimiter) { - initErrorMessages(); - return StringUtils.arrayToDelimitedString(this.errorMessages, delimiter); + return StringUtils.arrayToDelimitedString(initErrorMessages(), delimiter); } /** * Extract the error messages from the ObjectError list. */ - private void initErrorMessages() throws NoSuchMessageException { + private String[] initErrorMessages() throws NoSuchMessageException { if (this.errorMessages == null) { - this.errorMessages = new String[this.objectErrors.size()]; - for (int i = 0; i < this.objectErrors.size(); i++) { - ObjectError error = this.objectErrors.get(i); - this.errorMessages[i] = this.requestContext.getMessage(error, this.htmlEscape); + if (this.objectErrors != null) { + this.errorMessages = new String[this.objectErrors.size()]; + for (int i = 0; i < this.objectErrors.size(); i++) { + ObjectError error = this.objectErrors.get(i); + this.errorMessages[i] = this.requestContext.getMessage(error, this.htmlEscape); + } + } + else { + this.errorMessages = new String[0]; } } + return this.errorMessages; } /** @@ -343,7 +356,7 @@ public class BindStatus { StringBuilder sb = new StringBuilder("BindStatus: "); sb.append("expression=[").append(this.expression).append("]; "); sb.append("value=[").append(this.value).append("]"); - if (isError()) { + if (!ObjectUtils.isEmpty(this.errorCodes)) { sb.append("; errorCodes=").append(Arrays.asList(this.errorCodes)); } return sb.toString(); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRendering.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRendering.java index 8ba67e59f2..a0032ff9ac 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRendering.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRendering.java @@ -39,12 +39,13 @@ class DefaultRendering implements Rendering { private final Map model; + @Nullable private final HttpStatus status; private final HttpHeaders headers; - DefaultRendering(Object view, @Nullable Model model, HttpStatus status, @Nullable HttpHeaders headers) { + DefaultRendering(Object view, @Nullable Model model, @Nullable HttpStatus status, @Nullable HttpHeaders headers) { this.view = view; this.model = (model != null ? model.asMap() : Collections.emptyMap()); this.status = status; @@ -63,6 +64,7 @@ class DefaultRendering implements Rendering { } @Override + @Nullable public HttpStatus status() { return this.status; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRenderingBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRenderingBuilder.java index 4f9ed63825..d4c86cc6eb 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRenderingBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultRenderingBuilder.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.web.reactive.result.view; import java.util.Arrays; @@ -20,6 +21,7 @@ import java.util.Map; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; import org.springframework.util.Assert; @@ -34,10 +36,13 @@ class DefaultRenderingBuilder implements Rendering.RedirectBuilder { private final Object view; + @Nullable private Model model; + @Nullable private HttpStatus status; + @Nullable private HttpHeaders headers; @@ -48,38 +53,35 @@ class DefaultRenderingBuilder implements Rendering.RedirectBuilder { @Override public DefaultRenderingBuilder modelAttribute(String name, Object value) { - initModel(); - this.model.addAttribute(name, value); + initModel().addAttribute(name, value); return this; } - private void initModel() { - if (this.model == null) { - this.model = new ExtendedModelMap(); - } - } - @Override public DefaultRenderingBuilder modelAttribute(Object value) { - initModel(); - this.model.addAttribute(value); + initModel().addAttribute(value); return this; } @Override public DefaultRenderingBuilder modelAttributes(Object... values) { - initModel(); - this.model.addAllAttributes(Arrays.asList(values)); + initModel().addAllAttributes(Arrays.asList(values)); return this; } @Override public DefaultRenderingBuilder model(Map map) { - initModel(); - this.model.addAllAttributes(map); + initModel().addAllAttributes(map); return this; } + private Model initModel() { + if (this.model == null) { + this.model = new ExtendedModelMap(); + } + return this.model; + } + @Override public DefaultRenderingBuilder status(HttpStatus status) { this.status = status; @@ -88,22 +90,21 @@ class DefaultRenderingBuilder implements Rendering.RedirectBuilder { @Override public DefaultRenderingBuilder header(String headerName, String... headerValues) { - initHeaders(); - this.headers.put(headerName, Arrays.asList(headerValues)); + initHeaders().put(headerName, Arrays.asList(headerValues)); return this; } @Override public DefaultRenderingBuilder headers(HttpHeaders headers) { - initHeaders(); - this.headers.putAll(headers); + initHeaders().putAll(headers); return this; } - private void initHeaders() { + private HttpHeaders initHeaders() { if (this.headers == null) { this.headers = new HttpHeaders(); } + return this.headers; } @Override @@ -123,6 +124,7 @@ class DefaultRenderingBuilder implements Rendering.RedirectBuilder { return (RedirectView) this.view; } + @Override public Rendering build() { return new DefaultRendering(this.view, this.model, this.status, this.headers); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RequestContext.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RequestContext.java index 5c20384177..f36eac690c 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RequestContext.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RequestContext.java @@ -65,10 +65,13 @@ public class RequestContext { private TimeZone timeZone; + @Nullable private Boolean defaultHtmlEscape; + @Nullable private Map errorsMap; + @Nullable private RequestDataValueProcessor dataValueProcessor; @@ -79,19 +82,21 @@ public class RequestContext { public RequestContext(ServerWebExchange exchange, Map model, MessageSource messageSource, @Nullable RequestDataValueProcessor dataValueProcessor) { - Assert.notNull(exchange, "'exchange' is required"); - Assert.notNull(model, "'model' is required"); - Assert.notNull(messageSource, "'messageSource' is required"); + Assert.notNull(exchange, "ServerWebExchange is required"); + Assert.notNull(model, "Model is required"); + Assert.notNull(messageSource, "MessageSource is required"); this.exchange = exchange; this.model = model; this.messageSource = messageSource; LocaleContext localeContext = exchange.getLocaleContext(); - this.locale = localeContext.getLocale(); - this.timeZone = (localeContext instanceof TimeZoneAwareLocaleContext ? - ((TimeZoneAwareLocaleContext)localeContext).getTimeZone() : TimeZone.getDefault()); + Locale locale = localeContext.getLocale(); + this.locale = (locale != null ? locale : Locale.getDefault()); + TimeZone timeZone = (localeContext instanceof TimeZoneAwareLocaleContext ? + ((TimeZoneAwareLocaleContext) localeContext).getTimeZone() : null); + this.timeZone = (timeZone != null ? timeZone : TimeZone.getDefault()); - this.defaultHtmlEscape = null; // TODO + this.defaultHtmlEscape = null; // TODO this.dataValueProcessor = dataValueProcessor; } @@ -125,7 +130,6 @@ public class RequestContext { /** * Return the current TimeZone. - * TODO: currently this is the Timezone.getDefault() */ public TimeZone getTimeZone() { return this.timeZone; @@ -168,6 +172,7 @@ public class RequestContext { * specified and an explicit value. * @return whether default HTML escaping is enabled (null = no explicit default) */ + @Nullable public Boolean getDefaultHtmlEscape() { return this.defaultHtmlEscape; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/freemarker/FreeMarkerConfigurer.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/freemarker/FreeMarkerConfigurer.java index 5e9b407dca..a34b3ca962 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/freemarker/FreeMarkerConfigurer.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/freemarker/FreeMarkerConfigurer.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. @@ -26,7 +26,9 @@ import freemarker.template.TemplateException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ResourceLoaderAware; +import org.springframework.lang.Nullable; import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory; +import org.springframework.util.Assert; /** * Configures FreeMarker for web usage via the "configLocation" and/or @@ -62,6 +64,7 @@ import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory; public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory implements FreeMarkerConfig, InitializingBean, ResourceLoaderAware { + @Nullable private Configuration configuration; @@ -111,7 +114,8 @@ public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory */ @Override public Configuration getConfiguration() { + Assert.state(this.configuration != null, "No Configuration available"); return this.configuration; } -} \ No newline at end of file +} diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/script/ScriptTemplateView.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/script/ScriptTemplateView.java index 2548c3aceb..1018fd004a 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/script/ScriptTemplateView.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/script/ScriptTemplateView.java @@ -37,7 +37,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; @@ -74,22 +73,28 @@ public class ScriptTemplateView extends AbstractUrlBasedView { private static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:"; + @Nullable private ScriptEngine engine; + @Nullable private String engineName; + @Nullable private Boolean sharedEngine; + @Nullable private String[] scripts; + @Nullable private String renderObject; + @Nullable private String renderFunction; + @Nullable private String[] resourceLoaderPaths; - private ResourceLoader resourceLoader; - + @Nullable private volatile ScriptEngineManager scriptEngineManager; @@ -193,9 +198,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView { String resourceLoaderPath = viewConfig.getResourceLoaderPath(); setResourceLoaderPath(resourceLoaderPath == null ? DEFAULT_RESOURCE_LOADER_PATH : resourceLoaderPath); } - if (this.resourceLoader == null) { - this.resourceLoader = getApplicationContext(); - } if (this.sharedEngine == null && viewConfig.isSharedEngine() != null) { this.sharedEngine = viewConfig.isSharedEngine(); } @@ -214,24 +216,34 @@ public class ScriptTemplateView extends AbstractUrlBasedView { loadScripts(this.engine); } else { - setEngine(createEngineFromName()); + setEngine(createEngineFromName(this.engineName)); } if (this.renderFunction != null && this.engine != null) { - Assert.isInstanceOf(Invocable.class, this.engine, "ScriptEngine must implement Invocable when 'renderFunction' is specified."); + Assert.isInstanceOf(Invocable.class, this.engine, + "ScriptEngine must implement Invocable when 'renderFunction' is specified"); } } protected ScriptEngine getEngine() { - return Boolean.FALSE.equals(this.sharedEngine) ? createEngineFromName() : this.engine; + if (Boolean.FALSE.equals(this.sharedEngine)) { + Assert.state(this.engineName != null, "No engine name specified"); + return createEngineFromName(this.engineName); + } + else { + Assert.state(this.engine != null, "No shared engine available"); + return this.engine; + } } - protected ScriptEngine createEngineFromName() { - if (this.scriptEngineManager == null) { - this.scriptEngineManager = new ScriptEngineManager(obtainApplicationContext().getClassLoader()); + protected ScriptEngine createEngineFromName(String engineName) { + ScriptEngineManager scriptEngineManager = this.scriptEngineManager; + if (scriptEngineManager == null) { + scriptEngineManager = new ScriptEngineManager(obtainApplicationContext().getClassLoader()); + this.scriptEngineManager = scriptEngineManager; } - ScriptEngine engine = StandardScriptUtils.retrieveEngineByName(this.scriptEngineManager, this.engineName); + ScriptEngine engine = StandardScriptUtils.retrieveEngineByName(scriptEngineManager, engineName); loadScripts(engine); return engine; } @@ -255,10 +267,12 @@ public class ScriptTemplateView extends AbstractUrlBasedView { @Nullable protected Resource getResource(String location) { - for (String path : this.resourceLoaderPaths) { - Resource resource = this.resourceLoader.getResource(path + location); - if (resource.exists()) { - return resource; + if (this.resourceLoaderPaths != null) { + for (String path : this.resourceLoaderPaths) { + Resource resource = obtainApplicationContext().getResource(path + location); + if (resource.exists()) { + return resource; + } } } return null; @@ -317,10 +331,10 @@ public class ScriptTemplateView extends AbstractUrlBasedView { } else if (this.renderObject != null) { Object thiz = engine.eval(this.renderObject); - html = ((Invocable)engine).invokeMethod(thiz, this.renderFunction, template, model, context); + html = ((Invocable) engine).invokeMethod(thiz, this.renderFunction, template, model, context); } else { - html = ((Invocable)engine).invokeFunction(this.renderFunction, template, model, context); + html = ((Invocable) engine).invokeFunction(this.renderFunction, template, model, context); } byte[] bytes = String.valueOf(html).getBytes(StandardCharsets.UTF_8); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/CloseStatus.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/CloseStatus.java index 70a2cfb4e2..eee89a0a16 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/CloseStatus.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/CloseStatus.java @@ -135,6 +135,7 @@ public final class CloseStatus { private final int code; + @Nullable private final String reason; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/HandshakeInfo.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/HandshakeInfo.java index e7234da290..0a7f6d4291 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/HandshakeInfo.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/HandshakeInfo.java @@ -41,6 +41,7 @@ public class HandshakeInfo { private final HttpHeaders headers; + @Nullable private final String protocol; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/AbstractListenerWebSocketSession.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/AbstractListenerWebSocketSession.java index 3650248c52..a4d8e4f825 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/AbstractListenerWebSocketSession.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/AbstractListenerWebSocketSession.java @@ -30,6 +30,7 @@ import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.http.server.reactive.AbstractListenerReadPublisher; import org.springframework.http.server.reactive.AbstractListenerWriteProcessor; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.web.reactive.socket.CloseStatus; import org.springframework.web.reactive.socket.HandshakeInfo; import org.springframework.web.reactive.socket.WebSocketMessage; @@ -58,10 +59,12 @@ public abstract class AbstractListenerWebSocketSession extends AbstractWebSoc private static final int RECEIVE_BUFFER_SIZE = 8192; + @Nullable private final MonoProcessor completionMono; private final WebSocketReceivePublisher receivePublisher = new WebSocketReceivePublisher(); + @Nullable private volatile WebSocketSendProcessor sendProcessor; private final AtomicBoolean sendCalled = new AtomicBoolean(); @@ -93,7 +96,9 @@ public abstract class AbstractListenerWebSocketSession extends AbstractWebSoc protected WebSocketSendProcessor getSendProcessor() { - return this.sendProcessor; + WebSocketSendProcessor sendProcessor = this.sendProcessor; + Assert.state(sendProcessor != null, "No WebSocketSendProcessor available"); + return sendProcessor; } @Override @@ -106,10 +111,11 @@ public abstract class AbstractListenerWebSocketSession extends AbstractWebSoc @Override public Mono send(Publisher messages) { if (this.sendCalled.compareAndSet(false, true)) { - this.sendProcessor = new WebSocketSendProcessor(); + WebSocketSendProcessor sendProcessor = new WebSocketSendProcessor(); + this.sendProcessor = sendProcessor; return Mono.from(subscriber -> { - messages.subscribe(this.sendProcessor); - this.sendProcessor.subscribe(subscriber); + messages.subscribe(sendProcessor); + sendProcessor.subscribe(subscriber); }); } else { @@ -157,18 +163,20 @@ public abstract class AbstractListenerWebSocketSession extends AbstractWebSoc /** Handle an error callback from the WebSocketHandler adapter */ void handleError(Throwable ex) { this.receivePublisher.onError(ex); - if (this.sendProcessor != null) { - this.sendProcessor.cancel(); - this.sendProcessor.onError(ex); + WebSocketSendProcessor sendProcessor = this.sendProcessor; + if (sendProcessor != null) { + sendProcessor.cancel(); + sendProcessor.onError(ex); } } /** Handle a close callback from the WebSocketHandler adapter */ void handleClose(CloseStatus reason) { this.receivePublisher.onAllDataRead(); - if (this.sendProcessor != null) { - this.sendProcessor.cancel(); - this.sendProcessor.onComplete(); + WebSocketSendProcessor sendProcessor = this.sendProcessor; + if (sendProcessor != null) { + sendProcessor.cancel(); + sendProcessor.onComplete(); } } @@ -205,6 +213,7 @@ public abstract class AbstractListenerWebSocketSession extends AbstractWebSoc private final class WebSocketReceivePublisher extends AbstractListenerReadPublisher { + @Nullable private volatile WebSocketMessage webSocketMessage; @Override diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketHandlerAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketHandlerAdapter.java index fc1ed072ca..dba31c6f11 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketHandlerAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketHandlerAdapter.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.websocket.api.extensions.Frame; import org.eclipse.jetty.websocket.common.OpCode; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.socket.CloseStatus; import org.springframework.web.reactive.socket.WebSocketHandler; @@ -56,6 +57,7 @@ public class JettyWebSocketHandlerAdapter { private final Function sessionFactory; + @Nullable private JettyWebSocketSession delegateSession; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketSession.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketSession.java index cf030bed8b..02ecae135a 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketSession.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/JettyWebSocketSession.java @@ -45,6 +45,7 @@ import org.springframework.web.reactive.socket.WebSocketSession; */ public class JettyWebSocketSession extends AbstractListenerWebSocketSession { + @Nullable private volatile SuspendToken suspendToken; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/StandardWebSocketHandlerAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/StandardWebSocketHandlerAdapter.java index 408b3657f0..cc7f2ab672 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/StandardWebSocketHandlerAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/adapter/StandardWebSocketHandlerAdapter.java @@ -26,6 +26,7 @@ import javax.websocket.PongMessage; import javax.websocket.Session; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.socket.CloseStatus; import org.springframework.web.reactive.socket.WebSocketHandler; @@ -47,6 +48,7 @@ public class StandardWebSocketHandlerAdapter extends Endpoint { private Function sessionFactory; + @Nullable private StandardWebSocketSession delegateSession; @@ -62,8 +64,8 @@ public class StandardWebSocketHandlerAdapter extends Endpoint { @Override public void onOpen(Session session, EndpointConfig config) { - this.delegateSession = this.sessionFactory.apply(session); + Assert.state(this.delegateSession != null, "No delegate session"); session.addMessageHandler(String.class, message -> { WebSocketMessage webSocketMessage = toMessage(message); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/client/UndertowWebSocketClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/client/UndertowWebSocketClient.java index 163185595d..c23b8579ee 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/client/UndertowWebSocketClient.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/client/UndertowWebSocketClient.java @@ -35,6 +35,7 @@ import reactor.core.publisher.MonoProcessor; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.socket.HandshakeInfo; import org.springframework.web.reactive.socket.WebSocketHandler; @@ -184,6 +185,7 @@ public class UndertowWebSocketClient extends WebSocketClientSupport implements W private final HttpHeaders responseHeaders = new HttpHeaders(); + @Nullable private final WebSocketClientNegotiation delegate; public DefaultNegotiation(List protocols, HttpHeaders requestHeaders, diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java index 034137bb85..93ec04797c 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java @@ -54,8 +54,10 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life new NamedThreadLocal<>("JettyWebSocketHandlerAdapter"); + @Nullable private WebSocketServerFactory factory; + @Nullable private volatile ServletContext servletContext; private volatile boolean running = false; @@ -66,10 +68,11 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life @Override public void start() { synchronized (this.lifecycleMonitor) { - if (!isRunning() && this.servletContext != null) { + ServletContext servletContext = this.servletContext; + if (!isRunning() && servletContext != null) { this.running = true; try { - this.factory = new WebSocketServerFactory(this.servletContext); + this.factory = new WebSocketServerFactory(servletContext); this.factory.setCreator((request, response) -> { WebSocketHandlerContainer container = adapterHolder.get(); String protocol = container.getProtocol(); @@ -92,11 +95,13 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life synchronized (this.lifecycleMonitor) { if (isRunning()) { this.running = false; - try { - this.factory.stop(); - } - catch (Throwable ex) { - throw new IllegalStateException("Failed to stop WebSocketServerFactory", ex); + if (this.factory != null) { + try { + this.factory.stop(); + } + catch (Throwable ex) { + throw new IllegalStateException("Failed to stop WebSocketServerFactory", ex); + } } } } @@ -125,6 +130,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life startLazily(servletRequest); + Assert.state(this.factory != null, "No WebSocketServerFactory available"); boolean isUpgrade = this.factory.isUpgradeRequest(servletRequest, servletResponse); Assert.isTrue(isUpgrade, "Not a WebSocket handshake"); @@ -175,6 +181,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life private final JettyWebSocketHandlerAdapter adapter; + @Nullable private final String protocol; public WebSocketHandlerContainer(JettyWebSocketHandlerAdapter adapter, @Nullable String protocol) { diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java index cb09196d46..f700e7f1c1 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java @@ -261,8 +261,6 @@ public class WebFluxConfigurationSupportTests { assertEquals(Ordered.LOWEST_PRECEDENCE - 1, handlerMapping.getOrder()); - assertNotNull(handlerMapping.getPatternRegistry()); - SimpleUrlHandlerMapping urlHandlerMapping = (SimpleUrlHandlerMapping) handlerMapping; WebHandler webHandler = (WebHandler) urlHandlerMapping.getUrlMap().get("/images/**"); assertNotNull(webHandler); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java index 59c5d0b58d..46883cdbe2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java @@ -307,30 +307,39 @@ public class DispatcherServlet extends FrameworkServlet { private boolean cleanupAfterInclude = true; /** MultipartResolver used by this servlet */ + @Nullable private MultipartResolver multipartResolver; /** LocaleResolver used by this servlet */ + @Nullable private LocaleResolver localeResolver; /** ThemeResolver used by this servlet */ + @Nullable private ThemeResolver themeResolver; /** List of HandlerMappings used by this servlet */ + @Nullable private List handlerMappings; /** List of HandlerAdapters used by this servlet */ + @Nullable private List handlerAdapters; /** List of HandlerExceptionResolvers used by this servlet */ + @Nullable private List handlerExceptionResolvers; /** RequestToViewNameTranslator used by this servlet */ + @Nullable private RequestToViewNameTranslator viewNameTranslator; /** FlashMapManager used by this servlet */ + @Nullable private FlashMapManager flashMapManager; /** List of ViewResolvers used by this servlet */ + @Nullable private List viewResolvers; @@ -893,12 +902,14 @@ public class DispatcherServlet extends FrameworkServlet { request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); - FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); - if (inputFlashMap != null) { - request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); + if (this.flashMapManager != null) { + FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); + if (inputFlashMap != null) { + request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); + } + request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); + request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } - request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); - request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { doDispatch(request, response); @@ -941,7 +952,7 @@ public class DispatcherServlet extends FrameworkServlet { // Determine handler for the current request. mappedHandler = getHandler(processedRequest); - if (mappedHandler == null || mappedHandler.getHandler() == null) { + if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } @@ -1076,11 +1087,12 @@ public class DispatcherServlet extends FrameworkServlet { */ @Override protected LocaleContext buildLocaleContext(final HttpServletRequest request) { - if (this.localeResolver instanceof LocaleContextResolver) { - return ((LocaleContextResolver) this.localeResolver).resolveLocaleContext(request); + LocaleResolver lr = this.localeResolver; + if (lr instanceof LocaleContextResolver) { + return ((LocaleContextResolver) lr).resolveLocaleContext(request); } else { - return () -> localeResolver.resolveLocale(request); + return () -> (lr != null ? lr.resolveLocale(request) : request.getLocale()); } } @@ -1140,10 +1152,12 @@ public class DispatcherServlet extends FrameworkServlet { * @see MultipartResolver#cleanupMultipart */ protected void cleanupMultipart(HttpServletRequest request) { - MultipartHttpServletRequest multipartRequest = - WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); - if (multipartRequest != null) { - this.multipartResolver.cleanupMultipart(multipartRequest); + if (this.multipartResolver != null) { + MultipartHttpServletRequest multipartRequest = + WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); + if (multipartRequest != null) { + this.multipartResolver.cleanupMultipart(multipartRequest); + } } } @@ -1155,14 +1169,16 @@ public class DispatcherServlet extends FrameworkServlet { */ @Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { - for (HandlerMapping hm : this.handlerMappings) { - if (logger.isTraceEnabled()) { - logger.trace( - "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); - } - HandlerExecutionChain handler = hm.getHandler(request); - if (handler != null) { - return handler; + if (this.handlerMappings != null) { + for (HandlerMapping hm : this.handlerMappings) { + if (logger.isTraceEnabled()) { + logger.trace( + "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); + } + HandlerExecutionChain handler = hm.getHandler(request); + if (handler != null) { + return handler; + } } } return null; @@ -1194,12 +1210,14 @@ public class DispatcherServlet extends FrameworkServlet { * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error. */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { - for (HandlerAdapter ha : this.handlerAdapters) { - if (logger.isTraceEnabled()) { - logger.trace("Testing handler adapter [" + ha + "]"); - } - if (ha.supports(handler)) { - return ha; + if (this.handlerAdapters != null) { + for (HandlerAdapter ha : this.handlerAdapters) { + if (logger.isTraceEnabled()) { + logger.trace("Testing handler adapter [" + ha + "]"); + } + if (ha.supports(handler)) { + return ha; + } } } throw new ServletException("No adapter for handler [" + handler + @@ -1222,10 +1240,12 @@ public class DispatcherServlet extends FrameworkServlet { // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; - for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) { - exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); - if (exMv != null) { - break; + if (this.handlerExceptionResolvers != null) { + for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) { + exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); + if (exMv != null) { + break; + } } } if (exMv != null) { @@ -1261,7 +1281,8 @@ public class DispatcherServlet extends FrameworkServlet { */ protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. - Locale locale = this.localeResolver.resolveLocale(request); + Locale locale = + (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; @@ -1310,7 +1331,7 @@ public class DispatcherServlet extends FrameworkServlet { */ @Nullable protected String getDefaultViewName(HttpServletRequest request) throws Exception { - return this.viewNameTranslator.getViewName(request); + return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null); } /** @@ -1331,10 +1352,12 @@ public class DispatcherServlet extends FrameworkServlet { protected View resolveViewName(String viewName, @Nullable Map model, Locale locale, HttpServletRequest request) throws Exception { - for (ViewResolver viewResolver : this.viewResolvers) { - View view = viewResolver.resolveViewName(viewName, locale); - if (view != null) { - return view; + if (this.viewResolvers != null) { + for (ViewResolver viewResolver : this.viewResolvers) { + View view = viewResolver.resolveViewName(viewName, locale); + if (view != null) { + return view; + } } } return null; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/FlashMap.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/FlashMap.java index 2d6af88e83..329f459a66 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/FlashMap.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/FlashMap.java @@ -49,6 +49,7 @@ import org.springframework.util.StringUtils; @SuppressWarnings("serial") public final class FlashMap extends HashMap implements Comparable { + @Nullable private String targetRequestPath; private final MultiValueMap targetRequestParams = new LinkedMultiValueMap<>(4); @@ -90,8 +91,8 @@ public final class FlashMap extends HashMap implements Comparabl /** * Provide a request parameter identifying the request for this FlashMap. - * @param name the expected parameter name (skipped if empty or {@code null}) - * @param value the expected value (skipped if empty or {@code null}) + * @param name the expected parameter name (skipped if empty) + * @param value the expected value (skipped if empty) */ public FlashMap addTargetRequestParam(String name, String value) { if (StringUtils.hasText(name) && StringUtils.hasText(value)) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java index eb5887eda2..087fe2d904 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java @@ -164,18 +164,22 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic /** ServletContext attribute to find the WebApplicationContext in */ + @Nullable private String contextAttribute; /** WebApplicationContext implementation class to create */ private Class contextClass = DEFAULT_CONTEXT_CLASS; /** WebApplicationContext id to assign */ + @Nullable private String contextId; /** Namespace for this servlet */ + @Nullable private String namespace; /** Explicit context config location */ + @Nullable private String contextConfigLocation; /** Actual ApplicationContextInitializer instances to apply to the context */ @@ -183,6 +187,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic new ArrayList<>(); /** Comma-delimited ApplicationContextInitializer class names set through init param */ + @Nullable private String contextInitializerClasses; /** Should we publish the context as a ServletContext attribute? */ @@ -201,6 +206,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic private boolean dispatchTraceRequest = false; /** WebApplicationContext for this servlet */ + @Nullable private WebApplicationContext webApplicationContext; /** If the WebApplicationContext was injected via {@link #setApplicationContext} */ @@ -769,6 +775,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic /** * Return this servlet's WebApplicationContext. */ + @Nullable public final WebApplicationContext getWebApplicationContext() { return this.webApplicationContext; } @@ -1065,7 +1072,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic private void publishRequestHandledEvent(HttpServletRequest request, HttpServletResponse response, long startTime, @Nullable Throwable failureCause) { - if (this.publishEvents) { + if (this.publishEvents && this.webApplicationContext != null) { // Whether or not we succeeded, publish an event. long processingTime = System.currentTimeMillis() - startTime; this.webApplicationContext.publishEvent( diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerExecutionChain.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerExecutionChain.java index 5a78d2b33a..6867a56950 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerExecutionChain.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerExecutionChain.java @@ -42,8 +42,10 @@ public class HandlerExecutionChain { private final Object handler; + @Nullable private HandlerInterceptor[] interceptors; + @Nullable private List interceptorList; private int interceptorIndex = -1; @@ -53,7 +55,7 @@ public class HandlerExecutionChain { * Create a new HandlerExecutionChain. * @param handler the handler object to execute */ - public HandlerExecutionChain(@Nullable Object handler) { + public HandlerExecutionChain(Object handler) { this(handler, (HandlerInterceptor[]) null); } @@ -63,7 +65,7 @@ public class HandlerExecutionChain { * @param interceptors the array of interceptors to apply * (in the given order) before the handler itself executes */ - public HandlerExecutionChain(@Nullable Object handler, @Nullable HandlerInterceptor... interceptors) { + public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) { if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain) handler; this.handler = originalChain.getHandler(); @@ -80,9 +82,7 @@ public class HandlerExecutionChain { /** * Return the handler object to execute. - * @return the handler object (may be {@code null}) */ - @Nullable public Object getHandler() { return this.handler; } @@ -207,9 +207,6 @@ public class HandlerExecutionChain { @Override public String toString() { Object handler = getHandler(); - if (handler == null) { - return "HandlerExecutionChain with no handler"; - } StringBuilder sb = new StringBuilder(); sb.append("HandlerExecutionChain with handler [").append(handler).append("]"); HandlerInterceptor[] interceptors = getInterceptors(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java index ab3db1db10..598ff76269 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java @@ -84,6 +84,7 @@ public abstract class HttpServletBean extends HttpServlet implements Environment /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private ConfigurableEnvironment environment; private final Set requiredProperties = new HashSet<>(4); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java index 27c46011d0..7d66dabc71 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java @@ -47,12 +47,15 @@ import org.springframework.util.CollectionUtils; public class ModelAndView { /** View instance or view name String */ + @Nullable private Object view; /** Model Map */ + @Nullable private ModelMap model; /** Optional HTTP status for the response */ + @Nullable private HttpStatus status; /** Indicates whether or not this instance has been cleared with a call to {@link #clear()} */ diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/RequestToViewNameTranslator.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/RequestToViewNameTranslator.java index 8eeffd5e47..bac2fdd984 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/RequestToViewNameTranslator.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/RequestToViewNameTranslator.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. @@ -35,7 +35,7 @@ public interface RequestToViewNameTranslator { * Translate the given {@link HttpServletRequest} into a view name. * @param request the incoming {@link HttpServletRequest} providing * the context from which a view name is to be resolved - * @return the view name (or {@code null} if no default found) + * @return the view name, or {@code null} if no default found * @throws Exception if view name translation fails */ @Nullable diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java index 0fffc02ff0..24067eac40 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java @@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.util.AntPathMatcher; +import org.springframework.util.Assert; import org.springframework.util.PathMatcher; import org.springframework.util.StringUtils; import org.springframework.web.context.support.ServletContextResource; @@ -103,14 +104,18 @@ public class ResourceServlet extends HttpServletBean { public static final String RESOURCE_PARAM_NAME = "resource"; + @Nullable private String defaultUrl; + @Nullable private String allowedResources; + @Nullable private String contentType; private boolean applyLastModified = false; + @Nullable private PathMatcher pathMatcher; private long startupTime; @@ -267,9 +272,12 @@ public class ResourceServlet extends HttpServletBean { StringUtils.tokenizeToStringArray(resourceUrl, RESOURCE_URL_DELIMITERS); for (String url : resourceUrls) { // check whether URL matches allowed resources - if (this.allowedResources != null && !this.pathMatcher.match(this.allowedResources, url)) { - throw new ServletException("Resource [" + url + - "] does not match allowed pattern [" + this.allowedResources + "]"); + if (this.allowedResources != null) { + Assert.state(this.pathMatcher != null, "No PathMatcher available"); + if (!this.pathMatcher.match(this.allowedResources, url)) { + throw new ServletException("Resource [" + url + + "] does not match allowed pattern [" + this.allowedResources + "]"); + } } if (logger.isDebugEnabled()) { logger.debug("Including resource [" + url + "]"); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java index 18d97ba60c..b5ff2cb608 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer.java @@ -96,8 +96,10 @@ public class ContentNegotiationConfigurer { /** * Class constructor with {@link javax.servlet.ServletContext}. */ - public ContentNegotiationConfigurer(ServletContext servletContext) { - this.factory.setServletContext(servletContext); + public ContentNegotiationConfigurer(@Nullable ServletContext servletContext) { + if (servletContext != null) { + this.factory.setServletContext(servletContext); + } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurer.java index b20139b17a..c19bf07ad9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurer.java @@ -47,6 +47,7 @@ public class DefaultServletHandlerConfigurer { private final ServletContext servletContext; + @Nullable private DefaultServletHttpRequestHandler handler; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java index 1e98bc9d3a..b11e76e36a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java @@ -20,7 +20,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.springframework.core.Ordered; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.PathMatcher; import org.springframework.util.StringUtils; @@ -44,6 +44,7 @@ public class InterceptorRegistration { private int order = 0; + @Nullable private PathMatcher pathMatcher; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/RedirectViewControllerRegistration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/RedirectViewControllerRegistration.java index 7a0fb28266..612b7938f5 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/RedirectViewControllerRegistration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/RedirectViewControllerRegistration.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. @@ -18,6 +18,7 @@ package org.springframework.web.servlet.config.annotation; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.servlet.mvc.ParameterizableViewController; import org.springframework.web.servlet.view.RedirectView; @@ -49,7 +50,6 @@ public class RedirectViewControllerRegistration { /** * Set the specific redirect 3xx status code to use. - * *

If not set, {@link org.springframework.web.servlet.view.RedirectView} * will select {@code HttpStatus.MOVED_TEMPORARILY (302)} by default. */ @@ -63,7 +63,6 @@ public class RedirectViewControllerRegistration { * Whether to interpret a given redirect URL that starts with a slash ("/") * as relative to the current ServletContext, i.e. as relative to the web * application root. - * *

Default is {@code true}. */ public RedirectViewControllerRegistration setContextRelative(boolean contextRelative) { @@ -74,7 +73,6 @@ public class RedirectViewControllerRegistration { /** * Whether to propagate the query parameters of the current request through * to the target redirect URL. - * *

Default is {@code false}. */ public RedirectViewControllerRegistration setKeepQueryParams(boolean propagate) { @@ -82,7 +80,7 @@ public class RedirectViewControllerRegistration { return this; } - protected void setApplicationContext(ApplicationContext applicationContext) { + protected void setApplicationContext(@Nullable ApplicationContext applicationContext) { this.controller.setApplicationContext(applicationContext); this.redirectView.setApplicationContext(applicationContext); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java index 9ef04fce48..4370b8a22f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.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,8 +22,9 @@ import java.util.List; import org.springframework.cache.Cache; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import org.springframework.util.Assert; import org.springframework.http.CacheControl; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.web.servlet.resource.PathResourceResolver; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; @@ -43,10 +44,13 @@ public class ResourceHandlerRegistration { private final List locations = new ArrayList<>(); + @Nullable private Integer cachePeriod; + @Nullable private CacheControl cacheControl; + @Nullable private ResourceChainRegistration resourceChainRegistration; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java index 86a6a26f10..60f7663b97 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java @@ -56,6 +56,7 @@ public class ResourceHandlerRegistry { private final ApplicationContext applicationContext; + @Nullable private final ContentNegotiationManager contentNegotiationManager; private final List registrations = new ArrayList<>(); @@ -142,9 +143,11 @@ public class ResourceHandlerRegistry { for (ResourceHandlerRegistration registration : this.registrations) { for (String pathPattern : registration.getPathPatterns()) { ResourceHttpRequestHandler handler = registration.getRequestHandler(); + if (this.contentNegotiationManager != null) { + handler.setContentNegotiationManager(this.contentNegotiationManager); + } handler.setServletContext(this.servletContext); handler.setApplicationContext(this.applicationContext); - handler.setContentNegotiationManager(this.contentNegotiationManager); try { handler.afterPropertiesSet(); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.java index a494b7455a..d592307a7c 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.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. @@ -18,6 +18,7 @@ package org.springframework.web.servlet.config.annotation; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.servlet.RequestToViewNameTranslator; import org.springframework.web.servlet.mvc.ParameterizableViewController; @@ -44,7 +45,6 @@ public class ViewControllerRegistration { /** * Set the status code to set on the response. Optional. - * *

If not set the response status will be 200 (OK). */ public ViewControllerRegistration setStatusCode(HttpStatus statusCode) { @@ -54,19 +54,17 @@ public class ViewControllerRegistration { /** * Set the view name to return. Optional. - * *

If not specified, the view controller will return {@code null} as the * view name in which case the configured {@link RequestToViewNameTranslator} * will select the view name. The {@code DefaultRequestToViewNameTranslator} * for example translates "/foo/bar" to "foo/bar". - * * @see org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator */ public void setViewName(String viewName) { this.controller.setViewName(viewName); } - protected void setApplicationContext(ApplicationContext applicationContext) { + protected void setApplicationContext(@Nullable ApplicationContext applicationContext) { this.controller.setApplicationContext(applicationContext); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java index 0a28f73505..93ed1d25ae 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java @@ -39,11 +39,11 @@ public class ViewControllerRegistry { private final List registrations = new ArrayList<>(4); - private final List redirectRegistrations = - new ArrayList<>(10); + private final List redirectRegistrations = new ArrayList<>(10); private int order = 1; + @Nullable private ApplicationContext applicationContext; @@ -97,7 +97,7 @@ public class ViewControllerRegistry { this.order = order; } - protected void setApplicationContext(ApplicationContext applicationContext) { + protected void setApplicationContext(@Nullable ApplicationContext applicationContext) { this.applicationContext = applicationContext; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewResolverRegistry.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewResolverRegistry.java index 71ca63442b..eb2e23abdf 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewResolverRegistry.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ViewResolverRegistry.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.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.context.ApplicationContext; import org.springframework.core.Ordered; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.accept.ContentNegotiationManager; @@ -53,14 +54,18 @@ import org.springframework.web.servlet.view.tiles3.TilesViewResolver; */ public class ViewResolverRegistry { + @Nullable private ContentNegotiatingViewResolver contentNegotiatingResolver; private final List viewResolvers = new ArrayList<>(4); + @Nullable private Integer order; + @Nullable private ContentNegotiationManager contentNegotiationManager; + @Nullable private ApplicationContext applicationContext; @@ -98,15 +103,14 @@ public class ViewResolverRegistry { * media types requested by the client (e.g. in the Accept header). *

If invoked multiple times the provided default views will be added to * any other default views that may have been configured already. - * * @see ContentNegotiatingViewResolver#setDefaultViews */ public void enableContentNegotiation(boolean useNotAcceptableStatus, View... defaultViews) { - initContentNegotiatingViewResolver(defaultViews); - this.contentNegotiatingResolver.setUseNotAcceptableStatusCode(useNotAcceptableStatus); + ContentNegotiatingViewResolver vr = initContentNegotiatingViewResolver(defaultViews); + vr.setUseNotAcceptableStatusCode(useNotAcceptableStatus); } - private void initContentNegotiatingViewResolver(View[] defaultViews) { + private ContentNegotiatingViewResolver initContentNegotiatingViewResolver(View[] defaultViews) { // ContentNegotiatingResolver in the registry: elevate its precedence! this.order = (this.order != null ? this.order : Ordered.HIGHEST_PRECEDENCE); @@ -123,8 +127,11 @@ public class ViewResolverRegistry { this.contentNegotiatingResolver = new ContentNegotiatingViewResolver(); this.contentNegotiatingResolver.setDefaultViews(Arrays.asList(defaultViews)); this.contentNegotiatingResolver.setViewResolvers(this.viewResolvers); - this.contentNegotiatingResolver.setContentNegotiationManager(this.contentNegotiationManager); + if (this.contentNegotiationManager != null) { + this.contentNegotiatingResolver.setContentNegotiationManager(this.contentNegotiationManager); + } } + return this.contentNegotiatingResolver; } /** @@ -162,7 +169,7 @@ public class ViewResolverRegistry { * {@link org.springframework.web.servlet.view.tiles3.TilesConfigurer} bean. */ public UrlBasedViewResolverRegistration tiles() { - if (this.applicationContext != null && !hasBeanOfType(TilesConfigurer.class)) { + if (!checkBeanOfType(TilesConfigurer.class)) { throw new BeanInitializationException("In addition to a Tiles view resolver " + "there must also be a single TilesConfigurer bean in this web application context " + "(or its parent)."); @@ -179,7 +186,7 @@ public class ViewResolverRegistry { * {@link org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer} bean. */ public UrlBasedViewResolverRegistration freeMarker() { - if (this.applicationContext != null && !hasBeanOfType(FreeMarkerConfigurer.class)) { + if (!checkBeanOfType(FreeMarkerConfigurer.class)) { throw new BeanInitializationException("In addition to a FreeMarker view resolver " + "there must also be a single FreeMarkerConfig bean in this web application context " + "(or its parent): FreeMarkerConfigurer is the usual implementation. " + @@ -195,7 +202,7 @@ public class ViewResolverRegistry { * prefix and a default suffix of ".tpl". */ public UrlBasedViewResolverRegistration groovy() { - if (this.applicationContext != null && !hasBeanOfType(GroovyMarkupConfigurer.class)) { + if (!checkBeanOfType(GroovyMarkupConfigurer.class)) { throw new BeanInitializationException("In addition to a Groovy markup view resolver " + "there must also be a single GroovyMarkupConfig bean in this web application context " + "(or its parent): GroovyMarkupConfigurer is the usual implementation. " + @@ -211,7 +218,7 @@ public class ViewResolverRegistry { * @since 4.2 */ public UrlBasedViewResolverRegistration scriptTemplate() { - if (this.applicationContext != null && !hasBeanOfType(ScriptTemplateConfigurer.class)) { + if (!checkBeanOfType(ScriptTemplateConfigurer.class)) { throw new BeanInitializationException("In addition to a script template view resolver " + "there must also be a single ScriptTemplateConfig bean in this web application context " + "(or its parent): ScriptTemplateConfigurer is the usual implementation. " + @@ -262,11 +269,12 @@ public class ViewResolverRegistry { this.order = order; } - protected boolean hasBeanOfType(Class beanType) { - return !ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors( - this.applicationContext, beanType, false, false)); - } + private boolean checkBeanOfType(Class beanType) { + return (this.applicationContext == null || + !ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors( + this.applicationContext, beanType, false, false))); + } protected int getOrder() { return (this.order != null ? this.order : Ordered.LOWEST_PRECEDENCE); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index 6a9cd32b1c..1389bac33e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -25,8 +25,6 @@ import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; -import com.fasterxml.jackson.databind.ObjectMapper; - import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanInitializationException; @@ -58,6 +56,7 @@ import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConve import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.lang.Nullable; import org.springframework.util.AntPathMatcher; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.PathMatcher; import org.springframework.validation.Errors; @@ -198,22 +197,31 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv ClassUtils.isPresent("javax.json.bind.Jsonb", WebMvcConfigurationSupport.class.getClassLoader()); + @Nullable private ApplicationContext applicationContext; + @Nullable private ServletContext servletContext; + @Nullable private List interceptors; + @Nullable private PathMatchConfigurer pathMatchConfigurer; + @Nullable private ContentNegotiationManager contentNegotiationManager; + @Nullable private List argumentResolvers; + @Nullable private List returnValueHandlers; + @Nullable private List> messageConverters; + @Nullable private Map corsConfigurations; @@ -229,7 +237,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv * Return the associated Spring {@link ApplicationContext}. * @since 4.2 */ - public ApplicationContext getApplicationContext() { + @Nullable + public final ApplicationContext getApplicationContext() { return this.applicationContext; } @@ -246,7 +255,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv * Return the associated {@link javax.servlet.ServletContext}. * @since 4.2 */ - public ServletContext getServletContext() { + @Nullable + public final ServletContext getServletContext() { return this.servletContext; } @@ -383,7 +393,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv try { this.contentNegotiationManager = configurer.getContentNegotiationManager(); } - catch (Exception ex) { + catch (Throwable ex) { throw new BeanInitializationException("Could not create ContentNegotiationManager", ex); } } @@ -465,6 +475,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv */ @Bean public HandlerMapping resourceHandlerMapping() { + Assert.state(this.applicationContext != null, "No ApplicationContext set"); + Assert.state(this.servletContext != null, "No ServletContext set"); + ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext, this.servletContext, mvcContentNegotiationManager()); addResourceHandlers(registry); @@ -514,7 +527,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv */ @Bean public HandlerMapping defaultServletHandlerMapping() { - DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(servletContext); + Assert.state(this.servletContext != null, "No ServletContext set"); + DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext); configureDefaultServletHandling(configurer); AbstractHandlerMapping handlerMapping = configurer.getHandlerMapping(); handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping(); @@ -785,16 +799,22 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv } if (jackson2XmlPresent) { - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build(); - messageConverters.add(new MappingJackson2XmlHttpMessageConverter(objectMapper)); + Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml(); + if (this.applicationContext != null) { + builder.applicationContext(this.applicationContext); + } + messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build())); } else if (jaxb2Present) { messageConverters.add(new Jaxb2RootElementHttpMessageConverter()); } if (jackson2Present) { - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build(); - messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper)); + Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); + if (this.applicationContext != null) { + builder.applicationContext(this.applicationContext); + } + messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); } else if (gsonPresent) { messageConverters.add(new GsonHttpMessageConverter()); @@ -804,12 +824,18 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv } if (jackson2SmilePresent) { - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.smile().applicationContext(this.applicationContext).build(); - messageConverters.add(new MappingJackson2SmileHttpMessageConverter(objectMapper)); + Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile(); + if (this.applicationContext != null) { + builder.applicationContext(this.applicationContext); + } + messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build())); } if (jackson2CborPresent) { - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.cbor().applicationContext(this.applicationContext).build(); - messageConverters.add(new MappingJackson2CborHttpMessageConverter(objectMapper)); + Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor(); + if (this.applicationContext != null) { + builder.applicationContext(this.applicationContext); + } + messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build())); } } @@ -911,7 +937,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv exceptionHandlerResolver.setResponseBodyAdvice( Collections.singletonList(new JsonViewResponseBodyAdvice())); } - exceptionHandlerResolver.setApplicationContext(this.applicationContext); + if (this.applicationContext != null) { + exceptionHandlerResolver.setApplicationContext(this.applicationContext); + } exceptionHandlerResolver.afterPropertiesSet(); exceptionResolvers.add(exceptionHandlerResolver); @@ -947,7 +975,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv public ViewResolver mvcViewResolver() { ViewResolverRegistry registry = new ViewResolverRegistry(); registry.setContentNegotiationManager(mvcContentNegotiationManager()); - registry.setApplicationContext(this.applicationContext); + if (this.applicationContext != null) { + registry.setApplicationContext(this.applicationContext); + } configureViewResolvers(registry); if (registry.getViewResolvers().isEmpty()) { @@ -962,7 +992,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv composite.setOrder(registry.getOrder()); composite.setViewResolvers(registry.getViewResolvers()); composite.setApplicationContext(this.applicationContext); - composite.setServletContext(this.servletContext); + if (this.servletContext != null) { + composite.setServletContext(this.servletContext); + } return composite; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerExceptionResolver.java index 2178e41250..ff358d11e2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerExceptionResolver.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. @@ -51,10 +51,13 @@ public abstract class AbstractHandlerExceptionResolver implements HandlerExcepti private int order = Ordered.LOWEST_PRECEDENCE; + @Nullable private Set mappedHandlers; + @Nullable private Class[] mappedHandlerClasses; + @Nullable private Log warnLogger; private boolean preventResponseCaching = false; @@ -101,7 +104,6 @@ public abstract class AbstractHandlerExceptionResolver implements HandlerExcepti *

Default is no warn logging. Specify this setting to activate warn logging into a specific * category. Alternatively, override the {@link #logException} method for custom logging. * @see org.apache.commons.logging.LogFactory#getLog(String) - * @see org.apache.log4j.Logger#getLogger(String) * @see java.util.logging.Logger#getLogger(String) */ public void setWarnLogCategory(String loggerName) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java index 3cb79eb29d..39f590ec4f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java @@ -69,6 +69,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport private int order = Integer.MAX_VALUE; // default: same as non-Ordered + @Nullable private Object defaultHandler; private UrlPathHelper urlPathHelper = new UrlPathHelper(); @@ -481,6 +482,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport private class PreFlightHandler implements HttpRequestHandler, CorsConfigurationSource { + @Nullable private final CorsConfiguration config; public PreFlightHandler(@Nullable CorsConfiguration config) { @@ -501,6 +503,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource { + @Nullable private final CorsConfiguration config; public CorsInterceptor(@Nullable CorsConfiguration config) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java index 59a167b81b..b12c7cd904 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java @@ -88,6 +88,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap private boolean detectHandlerMethodsInAncestorContexts = false; + @Nullable private HandlerMethodMappingNamingStrategy namingStrategy; private final MappingRegistry mappingRegistry = new MappingRegistry(); @@ -683,6 +684,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap private final List directUrls; + @Nullable private final String mappingName; public MappingRegistration(T mapping, HandlerMethod handlerMethod, diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerExceptionResolverComposite.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerExceptionResolverComposite.java index c343cb265e..fd7a7f7c71 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerExceptionResolverComposite.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerExceptionResolverComposite.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. @@ -34,18 +34,11 @@ import org.springframework.web.servlet.ModelAndView; */ public class HandlerExceptionResolverComposite implements HandlerExceptionResolver, Ordered { + @Nullable private List resolvers; private int order = Ordered.LOWEST_PRECEDENCE; - public void setOrder(int order) { - this.order = order; - } - - @Override - public int getOrder() { - return this.order; - } /** * Set the list of exception resolvers to delegate to. @@ -58,21 +51,30 @@ public class HandlerExceptionResolverComposite implements HandlerExceptionResolv * Return the list of exception resolvers to delegate to. */ public List getExceptionResolvers() { - return Collections.unmodifiableList(resolvers); + return (this.resolvers != null ? Collections.unmodifiableList(this.resolvers) : Collections.emptyList()); } + public void setOrder(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return this.order; + } + + /** * Resolve the exception by iterating over the list of configured exception resolvers. * The first one to return a ModelAndView instance wins. Otherwise {@code null} is returned. */ @Override @Nullable - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, - @Nullable Object handler, - Exception ex) { - if (resolvers != null) { - for (HandlerExceptionResolver handlerExceptionResolver : resolvers) { + public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, + @Nullable Object handler,Exception ex) { + + if (this.resolvers != null) { + for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) { ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex); if (mav != null) { return mav; 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 2da809bd27..6151e5a264 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 @@ -45,12 +45,15 @@ import org.springframework.web.servlet.ModelAndView; */ public final class MappedInterceptor implements HandlerInterceptor { + @Nullable private final String[] includePatterns; + @Nullable private final String[] excludePatterns; private final HandlerInterceptor interceptor; + @Nullable private PathMatcher pathMatcher; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.java index acb2bc8921..4f98dd66e5 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleMappingExceptionResolver.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. @@ -21,7 +21,6 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -49,16 +48,21 @@ public class SimpleMappingExceptionResolver extends AbstractHandlerExceptionReso public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception"; + @Nullable private Properties exceptionMappings; + @Nullable private Class[] excludedExceptions; + @Nullable private String defaultErrorView; + @Nullable private Integer defaultStatusCode; private Map statusCodes = new HashMap<>(); + @Nullable private String exceptionAttribute = DEFAULT_EXCEPTION_ATTRIBUTE; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleServletPostProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleServletPostProcessor.java index 4a6df8fdeb..70278eb7fa 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleServletPostProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/SimpleServletPostProcessor.java @@ -69,8 +69,10 @@ public class SimpleServletPostProcessor implements private boolean useSharedServletConfig = true; + @Nullable private ServletContext servletContext; + @Nullable private ServletConfig servletConfig; @@ -140,9 +142,10 @@ public class SimpleServletPostProcessor implements private final String servletName; + @Nullable private final ServletContext servletContext; - public DelegatingServletConfig(String servletName, ServletContext servletContext) { + public DelegatingServletConfig(String servletName, @Nullable ServletContext servletContext) { this.servletName = servletName; this.servletContext = servletContext; } @@ -153,6 +156,7 @@ public class SimpleServletPostProcessor implements } @Override + @Nullable public ServletContext getServletContext() { return this.servletContext; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/UserRoleAuthorizationInterceptor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/UserRoleAuthorizationInterceptor.java index f8df232acb..6dd2c0919b 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/UserRoleAuthorizationInterceptor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/UserRoleAuthorizationInterceptor.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. @@ -21,6 +21,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.lang.Nullable; + /** * Interceptor that checks the authorization of the current user via the * user's roles, as evaluated by HttpServletRequest's isUserInRole method. @@ -31,6 +33,7 @@ import javax.servlet.http.HttpServletResponse; */ public class UserRoleAuthorizationInterceptor extends HandlerInterceptorAdapter { + @Nullable private String[] authorizedRoles; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletForwardingController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletForwardingController.java index dc3942dbc8..ef2933cdb2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletForwardingController.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletForwardingController.java @@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.BeanNameAware; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.util.WebUtils; @@ -87,8 +88,10 @@ import org.springframework.web.util.WebUtils; */ public class ServletForwardingController extends AbstractController implements BeanNameAware { + @Nullable private String servletName; + @Nullable private String beanName; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletWrappingController.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletWrappingController.java index ad23119c2e..08ded5a8e7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletWrappingController.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/ServletWrappingController.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.web.servlet.ModelAndView; @@ -84,14 +85,18 @@ import org.springframework.web.servlet.ModelAndView; public class ServletWrappingController extends AbstractController implements BeanNameAware, InitializingBean, DisposableBean { + @Nullable private Class servletClass; + @Nullable private String servletName; private Properties initParameters = new Properties(); + @Nullable private String beanName; + @Nullable private Servlet servletInstance; @@ -156,6 +161,7 @@ public class ServletWrappingController extends AbstractController protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { + Assert.state(this.servletInstance != null, "No Servlet instance"); this.servletInstance.service(request, response); return null; } @@ -167,7 +173,9 @@ public class ServletWrappingController extends AbstractController */ @Override public void destroy() { - this.servletInstance.destroy(); + if (this.servletInstance != null) { + this.servletInstance.destroy(); + } } @@ -179,6 +187,7 @@ public class ServletWrappingController extends AbstractController private class DelegatingServletConfig implements ServletConfig { @Override + @Nullable public String getServletName() { return servletName; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java index 893ed71d45..167fe78565 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java @@ -17,7 +17,6 @@ package org.springframework.web.servlet.mvc.annotation; import java.io.IOException; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -56,6 +55,7 @@ import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver; */ public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware { + @Nullable private MessageSource messageSource; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractNameValueExpression.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractNameValueExpression.java index f1ad3b838f..5fdb5df62a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractNameValueExpression.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractNameValueExpression.java @@ -18,6 +18,8 @@ package org.springframework.web.servlet.mvc.condition; import javax.servlet.http.HttpServletRequest; +import org.springframework.lang.Nullable; + /** * Supports "name=value" style expressions as described in: * {@link org.springframework.web.bind.annotation.RequestMapping#params()} and @@ -31,6 +33,7 @@ abstract class AbstractNameValueExpression implements NameValueExpression protected final String name; + @Nullable protected final T value; protected final boolean isNegated; @@ -40,12 +43,12 @@ abstract class AbstractNameValueExpression implements NameValueExpression int separator = expression.indexOf('='); if (separator == -1) { this.isNegated = expression.startsWith("!"); - this.name = isNegated ? expression.substring(1) : expression; + this.name = (this.isNegated ? expression.substring(1) : expression); this.value = null; } else { this.isNegated = (separator > 0) && (expression.charAt(separator - 1) == '!'); - this.name = isNegated ? expression.substring(0, separator - 1) : expression.substring(0, separator); + this.name = (this.isNegated ? expression.substring(0, separator - 1) : expression.substring(0, separator)); this.value = parseValue(expression.substring(separator + 1)); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java index a65f819989..d569bddb6e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java @@ -23,7 +23,6 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; - import javax.servlet.http.HttpServletRequest; import org.springframework.http.InvalidMediaTypeException; @@ -90,7 +89,7 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition { String getName(); + @Nullable T getValue(); boolean isNegated(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java index 088140d39d..aa9bcf3fe0 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java @@ -22,6 +22,7 @@ import java.util.LinkedHashSet; import java.util.Set; import javax.servlet.http.HttpServletRequest; +import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.util.WebUtils; @@ -141,12 +142,12 @@ public final class ParamsRequestCondition extends AbstractRequestCondition { + @Nullable private final RequestCondition condition; @@ -87,7 +87,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition combined = (RequestCondition) this.condition.combine(other.condition); return new RequestConditionHolder(combined); } @@ -96,9 +96,9 @@ public final class RequestConditionHolder extends AbstractRequestCondition clazz = this.condition.getClass(); - Class otherClazz = other.condition.getClass(); + private void assertEqualConditionTypes(RequestCondition thisCondition, RequestCondition otherCondition) { + Class clazz = thisCondition.getClass(); + Class otherClazz = otherCondition.getClass(); if (!clazz.equals(otherClazz)) { throw new ClassCastException("Incompatible request conditions: " + clazz + " and " + otherClazz); } @@ -135,7 +135,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition { + @Nullable private final String name; private final PatternsRequestCondition patternsCondition; @@ -418,8 +419,10 @@ public final class RequestMappingInfo implements RequestCondition customCondition; private BuilderConfiguration options = new BuilderConfiguration(); @@ -511,8 +514,10 @@ public final class RequestMappingInfo implements RequestCondition getFileExtensions() { - if (useRegisteredSuffixPatternMatch() && getContentNegotiationManager() != null) { + if (useRegisteredSuffixPatternMatch() && this.contentNegotiationManager != null) { return this.contentNegotiationManager.getAllFileExtensions(); } return null; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java index 205c919dc2..a378765f02 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java @@ -49,6 +49,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.StreamUtils; import org.springframework.validation.Errors; import org.springframework.validation.annotation.Validated; import org.springframework.web.HttpMediaTypeNotSupportedException; @@ -302,6 +303,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements private final HttpHeaders headers; + @Nullable private final InputStream body; public EmptyBodyCheckingHttpInputMessage(HttpInputMessage inputMessage) throws IOException { @@ -332,7 +334,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements @Override public InputStream getBody() { - return this.body; + return (this.body != null ? this.body : StreamUtils.emptyInput()); } public boolean hasBody() { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AsyncTaskMethodReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AsyncTaskMethodReturnValueHandler.java index b16f79cd9c..6b06a20c53 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AsyncTaskMethodReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AsyncTaskMethodReturnValueHandler.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. @@ -33,10 +33,11 @@ import org.springframework.web.method.support.ModelAndViewContainer; */ public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler { + @Nullable private final BeanFactory beanFactory; - public AsyncTaskMethodReturnValueHandler(BeanFactory beanFactory) { + public AsyncTaskMethodReturnValueHandler(@Nullable BeanFactory beanFactory) { this.beanFactory = beanFactory; } @@ -56,7 +57,9 @@ public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnVal } WebAsyncTask webAsyncTask = (WebAsyncTask) returnValue; - webAsyncTask.setBeanFactory(this.beanFactory); + if (this.beanFactory != null) { + webAsyncTask.setBeanFactory(this.beanFactory); + } WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java index 60121fb3b8..bd63b19017 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java @@ -75,12 +75,16 @@ import org.springframework.web.servlet.support.RequestContextUtils; public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver implements ApplicationContextAware, InitializingBean { + @Nullable private List customArgumentResolvers; + @Nullable private HandlerMethodArgumentResolverComposite argumentResolvers; + @Nullable private List customReturnValueHandlers; + @Nullable private HandlerMethodReturnValueHandlerComposite returnValueHandlers; private List> messageConverters; @@ -89,6 +93,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce private final List responseBodyAdvice = new ArrayList<>(); + @Nullable private ApplicationContext applicationContext; private final Map, ExceptionHandlerMethodResolver> exceptionHandlerCache = @@ -374,8 +379,12 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce return null; } - exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); - exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); + if (this.argumentResolvers != null) { + exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); + } + if (this.returnValueHandlers != null) { + exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); + } ServletWebRequest webRequest = new ServletWebRequest(request, response); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java index e6a3cb41a5..3d1e707074 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java @@ -17,7 +17,6 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.util.Map; - import javax.servlet.ServletRequest; import org.springframework.beans.MutablePropertyValues; @@ -51,7 +50,7 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder { * @param objectName the name of the target object * @see #DEFAULT_OBJECT_NAME */ - public ExtendedServletRequestDataBinder(@Nullable Object target, @Nullable String objectName) { + public ExtendedServletRequestDataBinder(@Nullable Object target, String objectName) { super(target, objectName); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewResolverMethodReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewResolverMethodReturnValueHandler.java index cd96487ad1..acff51a5fa 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewResolverMethodReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewResolverMethodReturnValueHandler.java @@ -55,6 +55,7 @@ import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver; */ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMethodReturnValueHandler { + @Nullable private final List mavResolvers; private final ModelAttributeMethodProcessor modelAttributeProcessor = new ModelAttributeMethodProcessor(true); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java index 9990632752..c10b22ccb8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java @@ -717,21 +717,14 @@ public class MvcUriComponentsBuilder { private static class ControllerMethodInvocationInterceptor implements org.springframework.cglib.proxy.MethodInterceptor, MethodInterceptor { - private static final Method getControllerMethod = - ReflectionUtils.findMethod(MethodInvocationInfo.class, "getControllerMethod"); - - private static final Method getArgumentValues = - ReflectionUtils.findMethod(MethodInvocationInfo.class, "getArgumentValues"); - - private static final Method getControllerType = - ReflectionUtils.findMethod(MethodInvocationInfo.class, "getControllerType"); + private final Class controllerType; + @Nullable private Method controllerMethod; + @Nullable private Object[] argumentValues; - private Class controllerType; - ControllerMethodInvocationInterceptor(Class controllerType) { this.controllerType = controllerType; } @@ -739,13 +732,13 @@ public class MvcUriComponentsBuilder { @Override @Nullable public Object intercept(Object obj, Method method, Object[] args, @Nullable MethodProxy proxy) { - if (method.equals(getControllerMethod)) { + if (method.getName().equals("getControllerMethod")) { return this.controllerMethod; } - else if (method.equals(getArgumentValues)) { + else if (method.getName().equals("getArgumentValues")) { return this.argumentValues; } - else if (method.equals(getControllerType)) { + else if (method.getName().equals("getControllerType")) { return this.controllerType; } else if (ReflectionUtils.isObjectMethod(method)) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandler.java index 250fab7298..9d11306645 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ReactiveTypeHandler.java @@ -180,10 +180,12 @@ class ReactiveTypeHandler { private final TaskExecutor taskExecutor; + @Nullable private Subscription subscription; private final AtomicReference elementRef = new AtomicReference<>(); + @Nullable private Throwable error; private volatile boolean terminated; @@ -219,7 +221,7 @@ class ReactiveTypeHandler { terminate(); this.emitter.complete(); }); - this.emitter.onError(t -> this.emitter.completeWithError(t)); + this.emitter.onError(this.emitter::completeWithError); subscription.request(1); } @@ -276,6 +278,7 @@ class ReactiveTypeHandler { Object element = this.elementRef.get(); if (element != null) { this.elementRef.lazySet(null); + Assert.state(this.subscription != null, "No subscription"); try { send(element); this.subscription.request(1); @@ -317,7 +320,9 @@ class ReactiveTypeHandler { private void terminate() { this.done = true; - this.subscription.cancel(); + if (this.subscription != null) { + this.subscription.cancel(); + } } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RedirectAttributesMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RedirectAttributesMethodArgumentResolver.java index 47d509ded8..fa65ff4ed3 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RedirectAttributesMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RedirectAttributesMethodArgumentResolver.java @@ -59,8 +59,8 @@ public class RedirectAttributesMethodArgumentResolver implements HandlerMethodAr ModelMap redirectAttributes; if (binderFactory != null) { - DataBinder dataBinder = binderFactory.createBinder(webRequest, null, null); - redirectAttributes = new RedirectAttributesModelMap(dataBinder); + DataBinder dataBinder = binderFactory.createBinder(webRequest, null, DataBinder.DEFAULT_OBJECT_NAME); + redirectAttributes = new RedirectAttributesModelMap(dataBinder); } else { redirectAttributes = new RedirectAttributesModelMap(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java index 7e28f12f91..64fb683c2f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java @@ -116,16 +116,22 @@ import org.springframework.web.util.WebUtils; public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { + @Nullable private List customArgumentResolvers; + @Nullable private HandlerMethodArgumentResolverComposite argumentResolvers; + @Nullable private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers; + @Nullable private List customReturnValueHandlers; + @Nullable private HandlerMethodReturnValueHandlerComposite returnValueHandlers; + @Nullable private List modelAndViewResolvers; private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); @@ -134,10 +140,12 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter private List requestResponseBodyAdvice = new ArrayList<>(); + @Nullable private WebBindingInitializer webBindingInitializer; private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync"); + @Nullable private Long asyncRequestTimeout; private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0]; @@ -156,21 +164,19 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); + @Nullable private ConfigurableBeanFactory beanFactory; - private final Map, SessionAttributesHandler> sessionAttributesHandlerCache = - new ConcurrentHashMap<>(64); + private final Map, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64); private final Map, Set> initBinderCache = new ConcurrentHashMap<>(64); - private final Map> initBinderAdviceCache = - new LinkedHashMap<>(); + private final Map> initBinderAdviceCache = new LinkedHashMap<>(); private final Map, Set> modelAttributeCache = new ConcurrentHashMap<>(64); - private final Map> modelAttributeAdviceCache = - new LinkedHashMap<>(); + private final Map> modelAttributeAdviceCache = new LinkedHashMap<>(); public RequestMappingHandlerAdapter() { @@ -284,7 +290,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter */ @Nullable public List getReturnValueHandlers() { - return this.returnValueHandlers.getHandlers(); + return (this.returnValueHandlers != null ? this.returnValueHandlers.getHandlers() : null); } /** @@ -310,7 +316,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter */ @Nullable public List getModelAndViewResolvers() { - return modelAndViewResolvers; + return this.modelAndViewResolvers; } /** @@ -827,8 +833,12 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); - invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); - invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); + if (this.argumentResolvers != null) { + invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); + } + if (this.returnValueHandlers != null) { + invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); + } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); @@ -905,7 +915,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) { InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method); - attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); + if (this.argumentResolvers != null) { + attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); + } attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); attrMethod.setDataBinderFactory(factory); return attrMethod; @@ -937,7 +949,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) { InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method); - binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers); + if (this.initBinderArgumentResolvers != null) { + binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers); + } binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer)); binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); return binderMethod; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java index 8d48239379..3386ccfc93 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java @@ -64,6 +64,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); + @Nullable private StringValueResolver embeddedValueResolver; private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitter.java index e59a8b07e0..97b7cf24d2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitter.java @@ -63,14 +63,17 @@ import org.springframework.util.ObjectUtils; */ public class ResponseBodyEmitter { + @Nullable private final Long timeout; private final Set earlySendAttempts = new LinkedHashSet<>(8); + @Nullable private Handler handler; private boolean complete; + @Nullable private Throwable failure; private final DefaultCallback timeoutCallback = new DefaultCallback(); @@ -270,6 +273,7 @@ public class ResponseBodyEmitter { private final Object data; + @Nullable private final MediaType mediaType; public DataWithMediaType(Object data, @Nullable MediaType mediaType) { @@ -290,6 +294,7 @@ public class ResponseBodyEmitter { private class DefaultCallback implements Runnable { + @Nullable private Runnable delegate; public void setDelegate(Runnable delegate) { @@ -308,6 +313,7 @@ public class ResponseBodyEmitter { private class ErrorCallback implements Consumer { + @Nullable private Consumer delegate; public void setDelegate(Consumer callback) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java index 5bc7d8a791..483e7e4cb8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java @@ -27,6 +27,7 @@ import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.http.HttpStatus; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ResponseBody; @@ -60,6 +61,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call"); + @Nullable private HandlerMethodReturnValueHandlerComposite returnValueHandlers; @@ -112,6 +114,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { } mavContainer.setRequestHandled(false); + Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); @@ -188,20 +191,19 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { private final MethodParameter returnType; public ConcurrentResultHandlerMethod(final Object result, ConcurrentResultMethodParameter returnType) { - super(new Callable() { - @Override - public Object call() throws Exception { - if (result instanceof Exception) { - throw (Exception) result; - } - else if (result instanceof Throwable) { - throw new NestedServletException("Async processing failed", (Throwable) result); - } - return result; + super((Callable) () -> { + if (result instanceof Exception) { + throw (Exception) result; } + else if (result instanceof Throwable) { + throw new NestedServletException("Async processing failed", (Throwable) result); + } + return result; }, CALLABLE_METHOD); - setHandlerMethodReturnValueHandlers(ServletInvocableHandlerMethod.this.returnValueHandlers); + if (ServletInvocableHandlerMethod.this.returnValueHandlers != null) { + setHandlerMethodReturnValueHandlers(ServletInvocableHandlerMethod.this.returnValueHandlers); + } this.returnType = returnType; } @@ -247,6 +249,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { */ private class ConcurrentResultMethodParameter extends HandlerMethodParameter { + @Nullable private final Object returnValue; private final ResolvableType returnType; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java index 592cc5baf4..a40aa2c9b5 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java @@ -128,7 +128,7 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr * @throws Exception */ @Nullable - protected Object createAttributeFromRequestValue(String sourceValue, @Nullable String attributeName, + protected Object createAttributeFromRequestValue(String sourceValue, String attributeName, MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestDataBinderFactory.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestDataBinderFactory.java index 66d510bee1..51d34a28c0 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestDataBinderFactory.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestDataBinderFactory.java @@ -49,7 +49,7 @@ public class ServletRequestDataBinderFactory extends InitBinderDataBinderFactory */ @Override protected ServletRequestDataBinder createBinderInstance( - @Nullable Object target, @Nullable String objectName, NativeWebRequest request) throws Exception { + @Nullable Object target, String objectName, NativeWebRequest request) throws Exception { return new ExtendedServletRequestDataBinder(target, objectName); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java index bab5e2d1b5..d863847b5d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java @@ -65,6 +65,7 @@ import org.springframework.web.servlet.support.RequestContextUtils; */ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver { + @Nullable private static final Method newPushBuilderMethod = ClassUtils.getMethodIfAvailable(HttpServletRequest.class, "newPushBuilder"); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java index f89f8d6354..5b585c5e2f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java @@ -189,6 +189,7 @@ public class SseEmitter extends ResponseBodyEmitter { private final Set dataToSend = new LinkedHashSet<>(4); + @Nullable private StringBuilder sb; @Override diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/RedirectAttributesModelMap.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/RedirectAttributesModelMap.java index d423310cff..825b043f4f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/RedirectAttributesModelMap.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/RedirectAttributesModelMap.java @@ -35,6 +35,7 @@ import org.springframework.validation.DataBinder; @SuppressWarnings("serial") public class RedirectAttributesModelMap extends ModelMap implements RedirectAttributes { + @Nullable private final DataBinder dataBinder; private final ModelMap flashAttributes = new ModelMap(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AppCacheManifestTransformer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AppCacheManifestTransformer.java index 0a37026555..f14a350d8e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AppCacheManifestTransformer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/AppCacheManifestTransformer.java @@ -217,6 +217,7 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport { private final String line; + @Nullable private final Resource resource; public LineOutput(String line, @Nullable Resource resource) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java index ce888f1964..a45d6e690e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java @@ -100,14 +100,19 @@ public class ResourceHttpRequestHandler extends WebContentGenerator private final List resourceTransformers = new ArrayList<>(4); + @Nullable private ResourceHttpMessageConverter resourceHttpMessageConverter; + @Nullable private ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter; + @Nullable private ContentNegotiationManager contentNegotiationManager; + @Nullable private PathExtensionContentNegotiationStrategy contentNegotiationStrategy; + @Nullable private CorsConfiguration corsConfiguration; @@ -176,14 +181,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator *

By default a {@link ResourceHttpMessageConverter} will be configured. * @since 4.3 */ - public void setResourceHttpMessageConverter(ResourceHttpMessageConverter resourceHttpMessageConverter) { - this.resourceHttpMessageConverter = resourceHttpMessageConverter; + public void setResourceHttpMessageConverter(ResourceHttpMessageConverter messageConverter) { + this.resourceHttpMessageConverter = messageConverter; } /** * Return the configured resource converter. * @since 4.3 */ + @Nullable public ResourceHttpMessageConverter getResourceHttpMessageConverter() { return this.resourceHttpMessageConverter; } @@ -193,14 +199,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator *

By default a {@link ResourceRegionHttpMessageConverter} will be configured. * @since 4.3 */ - public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter) { - this.resourceRegionHttpMessageConverter = resourceRegionHttpMessageConverter; + public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter messageConverter) { + this.resourceRegionHttpMessageConverter = messageConverter; } /** * Return the configured resource region converter. * @since 4.3 */ + @Nullable public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter() { return this.resourceRegionHttpMessageConverter; } @@ -368,10 +375,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response); if (request.getHeader(HttpHeaders.RANGE) == null) { + Assert.state(this.resourceHttpMessageConverter != null, "Not initialized"); setHeaders(response, resource, mediaType); this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage); } else { + Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized"); response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes"); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request); try { @@ -516,7 +525,8 @@ public class ResourceHttpRequestHandler extends WebContentGenerator */ @Nullable protected MediaType getMediaType(HttpServletRequest request, Resource resource) { - return this.contentNegotiationStrategy.getMediaTypeForResource(resource); + return (this.contentNegotiationStrategy != null ? + this.contentNegotiationStrategy.getMediaTypeForResource(resource) : null); } /** diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceTransformerSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceTransformerSupport.java index a8d7529975..fcfa967056 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceTransformerSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceTransformerSupport.java @@ -35,6 +35,7 @@ import org.springframework.util.StringUtils; */ public abstract class ResourceTransformerSupport implements ResourceTransformer { + @Nullable private ResourceUrlProvider resourceUrlProvider; @@ -43,15 +44,15 @@ public abstract class ResourceTransformerSupport implements ResourceTransformer * URL of links in a transformed resource (e.g. import links in a CSS file). * This is required only for links expressed as full paths and not for * relative links. - * @param resourceUrlProvider the URL provider to use */ public void setResourceUrlProvider(ResourceUrlProvider resourceUrlProvider) { this.resourceUrlProvider = resourceUrlProvider; } /** - * @return the configured {@code ResourceUrlProvider}. + * Return the configured {@code ResourceUrlProvider}. */ + @Nullable public ResourceUrlProvider getResourceUrlProvider() { return this.resourceUrlProvider; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java index 654e9fd432..4673b0908a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlEncodingFilter.java @@ -66,9 +66,10 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean { private final HttpServletRequest request; /* Cache the index and prefix of the path within the DispatcherServlet mapping */ + @Nullable private Integer indexLookupPath; - private String prefixLookupPath; + private String prefixLookupPath = ""; public ResourceUrlEncodingResponseWrapper(HttpServletRequest request, HttpServletResponse wrapped) { super(wrapped); @@ -83,11 +84,11 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean { return super.encodeURL(url); } - initLookupPath(resourceUrlProvider); + int index = initLookupPath(resourceUrlProvider); if (url.startsWith(this.prefixLookupPath)) { int suffixIndex = getQueryParamsIndex(url); String suffix = url.substring(suffixIndex); - String lookupPath = url.substring(this.indexLookupPath, suffixIndex); + String lookupPath = url.substring(index, suffixIndex); lookupPath = resourceUrlProvider.getForLookupPath(lookupPath); if (lookupPath != null) { return super.encodeURL(this.prefixLookupPath + lookupPath + suffix); @@ -103,14 +104,13 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean { ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR); } - private void initLookupPath(ResourceUrlProvider urlProvider) { + private int initLookupPath(ResourceUrlProvider urlProvider) { if (this.indexLookupPath == null) { UrlPathHelper pathHelper = urlProvider.getUrlPathHelper(); String requestUri = pathHelper.getRequestUri(this.request); String lookupPath = pathHelper.getLookupPathForRequest(this.request); this.indexLookupPath = requestUri.lastIndexOf(lookupPath); this.prefixLookupPath = requestUri.substring(0, this.indexLookupPath); - if ("/".equals(lookupPath) && !"/".equals(requestUri)) { String contextPath = pathHelper.getContextPath(this.request); if (requestUri.equals(contextPath)) { @@ -119,6 +119,7 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean { } } } + return this.indexLookupPath; } private int getQueryParamsIndex(String url) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/TransformedResource.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/TransformedResource.java index 414220ee59..75709e41ad 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/TransformedResource.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/TransformedResource.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. @@ -20,11 +20,12 @@ import java.io.IOException; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; /** - * An extension of {@link org.springframework.core.io.ByteArrayResource} - * that a {@link ResourceTransformer} can use to represent an original - * resource preserving all other information except the content. + * An extension of {@link ByteArrayResource} that a {@link ResourceTransformer} + * can use to represent an original resource preserving all other information + * except the content. * * @author Jeremy Grelle * @author Rossen Stoyanchev @@ -32,6 +33,7 @@ import org.springframework.core.io.Resource; */ public class TransformedResource extends ByteArrayResource { + @Nullable private final String filename; private final long lastModified; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java index 9487cbaf0d..bce5e8df68 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/BindStatus.java @@ -24,6 +24,7 @@ import org.springframework.beans.BeanWrapper; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.context.NoSuchMessageException; import org.springframework.lang.Nullable; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; @@ -54,24 +55,33 @@ public class BindStatus { private final boolean htmlEscape; + @Nullable private final String expression; + @Nullable private final Errors errors; + @Nullable private BindingResult bindingResult; + @Nullable private Object value; + @Nullable private Class valueType; + @Nullable private Object actualValue; + @Nullable private PropertyEditor editor; + @Nullable private List objectErrors; - private String[] errorCodes; + private String[] errorCodes = new String[0]; + @Nullable private String[] errorMessages; @@ -133,7 +143,7 @@ public class BindStatus { else { this.objectErrors = this.errors.getGlobalErrors(); } - initErrorCodes(); + initErrorCodes(this.objectErrors); } else { @@ -163,27 +173,14 @@ public class BindStatus { /** * Extract the error codes from the ObjectError list. */ - private void initErrorCodes() { - this.errorCodes = new String[this.objectErrors.size()]; - for (int i = 0; i < this.objectErrors.size(); i++) { - ObjectError error = this.objectErrors.get(i); + private void initErrorCodes(List objectErrors) { + this.errorCodes = new String[objectErrors.size()]; + for (int i = 0; i < objectErrors.size(); i++) { + ObjectError error = objectErrors.get(i); this.errorCodes[i] = error.getCode(); } } - /** - * Extract the error messages from the ObjectError list. - */ - private void initErrorMessages() throws NoSuchMessageException { - if (this.errorMessages == null) { - this.errorMessages = new String[this.objectErrors.size()]; - for (int i = 0; i < this.objectErrors.size(); i++) { - ObjectError error = this.objectErrors.get(i); - this.errorMessages[i] = this.requestContext.getMessage(error, this.htmlEscape); - } - } - } - /** * Return the bean and property path for which values and errors @@ -256,14 +253,13 @@ public class BindStatus { * Return if this status represents a field or object error. */ public boolean isError() { - return (this.errorCodes != null && this.errorCodes.length > 0); + return (this.errorCodes.length > 0); } /** * Return the error codes for the field or object, if any. * Returns an empty array instead of null if none. */ - @Nullable public String[] getErrorCodes() { return this.errorCodes; } @@ -280,16 +276,15 @@ public class BindStatus { * if any. Returns an empty array instead of null if none. */ public String[] getErrorMessages() { - initErrorMessages(); - return this.errorMessages; + return initErrorMessages(); } /** * Return the first error message for the field or object, if any. */ public String getErrorMessage() { - initErrorMessages(); - return (this.errorMessages.length > 0 ? this.errorMessages[0] : ""); + String[] errorMessages = initErrorMessages(); + return (errorMessages.length > 0 ? errorMessages[0] : ""); } /** @@ -299,8 +294,26 @@ public class BindStatus { * @return the error message string */ public String getErrorMessagesAsString(String delimiter) { - initErrorMessages(); - return StringUtils.arrayToDelimitedString(this.errorMessages, delimiter); + return StringUtils.arrayToDelimitedString(initErrorMessages(), delimiter); + } + + /** + * Extract the error messages from the ObjectError list. + */ + private String[] initErrorMessages() throws NoSuchMessageException { + if (this.errorMessages == null) { + if (this.objectErrors != null) { + this.errorMessages = new String[this.objectErrors.size()]; + for (int i = 0; i < this.objectErrors.size(); i++) { + ObjectError error = this.objectErrors.get(i); + this.errorMessages[i] = this.requestContext.getMessage(error, this.htmlEscape); + } + } + else { + this.errorMessages = new String[0]; + } + } + return this.errorMessages; } /** @@ -341,7 +354,7 @@ public class BindStatus { StringBuilder sb = new StringBuilder("BindStatus: "); sb.append("expression=[").append(this.expression).append("]; "); sb.append("value=[").append(this.value).append("]"); - if (isError()) { + if (!ObjectUtils.isEmpty(this.errorCodes)) { sb.append("; errorCodes=").append(Arrays.asList(this.errorCodes)); } return sb.toString(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java index 7012bd2d2a..f38222c680 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/RequestContext.java @@ -92,31 +92,43 @@ public class RequestContext { public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = RequestContext.class.getName() + ".CONTEXT"; - protected static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config", - RequestContext.class.getClassLoader()); + protected static final boolean jstlPresent = ClassUtils.isPresent( + "javax.servlet.jsp.jstl.core.Config", RequestContext.class.getClassLoader()); + @Nullable private HttpServletRequest request; + @Nullable private HttpServletResponse response; + @Nullable private Map model; + @Nullable private WebApplicationContext webApplicationContext; + @Nullable private Locale locale; + @Nullable private TimeZone timeZone; + @Nullable private Theme theme; + @Nullable private Boolean defaultHtmlEscape; + @Nullable private Boolean responseEncodedHtmlEscape; + @Nullable private UrlPathHelper urlPathHelper; + @Nullable private RequestDataValueProcessor requestDataValueProcessor; + @Nullable private Map errorsMap; @@ -214,15 +226,15 @@ public class RequestContext { * @param request current HTTP request * @param servletContext the servlet context of the web application (can be {@code null}; necessary for * fallback to root WebApplicationContext) - * @param model the model attributes for the current view (can be {@code null}, using the request attributes - * for Errors retrieval) + * @param model the model attributes for the current view (can be {@code null}, using the request + * attributes for Errors retrieval) * @see #getFallbackLocale * @see #getFallbackTheme * @see org.springframework.web.servlet.DispatcherServlet#LOCALE_RESOLVER_ATTRIBUTE * @see org.springframework.web.servlet.DispatcherServlet#THEME_RESOLVER_ATTRIBUTE */ - protected void initContext(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable ServletContext servletContext, - @Nullable Map model) { + protected void initContext(HttpServletRequest request, @Nullable HttpServletResponse response, + @Nullable ServletContext servletContext, @Nullable Map model) { this.request = request; this.response = response; @@ -267,7 +279,8 @@ public class RequestContext { // Determine response-encoded HTML escape setting from the "responseEncodedHtmlEscape" // context-param in web.xml, if any. - this.responseEncodedHtmlEscape = WebUtils.getResponseEncodedHtmlEscape(this.webApplicationContext.getServletContext()); + this.responseEncodedHtmlEscape = + WebUtils.getResponseEncodedHtmlEscape(this.webApplicationContext.getServletContext()); this.urlPathHelper = new UrlPathHelper(); @@ -776,8 +789,8 @@ public class RequestContext { * @return the message */ public String getThemeMessage(String code, @Nullable List args, String defaultMessage) { - return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null), defaultMessage, - this.locale); + return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null), + defaultMessage, this.locale); } /** diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java index 2b1508821a..17ac0343a9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java @@ -50,6 +50,7 @@ import org.springframework.web.util.UrlPathHelper; */ public class ServletUriComponentsBuilder extends UriComponentsBuilder { + @Nullable private String originalPath; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java index fd6615a762..ff1084e41d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java @@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.http.CacheControl; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpRequestMethodNotSupportedException; @@ -81,16 +82,20 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { /** Set of supported HTTP methods */ + @Nullable private Set supportedMethods; + @Nullable private String allowHeader; private boolean requireSession = false; + @Nullable private CacheControl cacheControl; private int cacheSeconds = -1; + @Nullable private String[] varyByRequestHeaders; @@ -159,8 +164,9 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { /** * Return the HTTP methods that this content generator supports. */ + @Nullable public final String[] getSupportedMethods() { - return StringUtils.toStringArray(this.supportedMethods); + return (this.supportedMethods != null ? StringUtils.toStringArray(this.supportedMethods) : null); } private void initAllowHeader() { @@ -193,6 +199,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { * requests are handled before making a call to * {@link #checkRequest(HttpServletRequest)}. */ + @Nullable protected String getAllowHeader() { return this.allowHeader; } @@ -225,6 +232,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { * that builds the Cache-Control HTTP response header. * @since 4.2 */ + @Nullable public final CacheControl getCacheControl() { return this.cacheControl; } @@ -269,6 +277,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { * Return the configured request header names for the "Vary" response header. * @since 4.3 */ + @Nullable public final String[] getVaryByRequestHeaders() { return this.varyByRequestHeaders; } @@ -391,7 +400,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { applyCacheSeconds(response, this.cacheSeconds); } if (this.varyByRequestHeaders != null) { - for (String value : getVaryRequestHeadersToAdd(response)) { + for (String value : getVaryRequestHeadersToAdd(response, this.varyByRequestHeaders)) { response.addHeader("Vary", value); } } @@ -587,18 +596,18 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { } - private Collection getVaryRequestHeadersToAdd(HttpServletResponse response) { + private Collection getVaryRequestHeadersToAdd(HttpServletResponse response, String[] varyByRequestHeaders) { if (!response.containsHeader(HttpHeaders.VARY)) { - return Arrays.asList(getVaryByRequestHeaders()); + return Arrays.asList(varyByRequestHeaders); } - Collection result = new ArrayList<>(getVaryByRequestHeaders().length); - Collections.addAll(result, getVaryByRequestHeaders()); + Collection result = new ArrayList<>(varyByRequestHeaders.length); + Collections.addAll(result, varyByRequestHeaders); for (String header : response.getHeaders(HttpHeaders.VARY)) { for (String existing : StringUtils.tokenizeToStringArray(header, ",")) { if ("*".equals(existing)) { return Collections.emptyList(); } - for (String value : getVaryByRequestHeaders()) { + for (String value : varyByRequestHeaders) { if (value.equalsIgnoreCase(existing)) { result.remove(value); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ArgumentTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ArgumentTag.java index 821e5e5e97..8cd0923af1 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ArgumentTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ArgumentTag.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,6 +19,8 @@ package org.springframework.web.servlet.tags; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; +import org.springframework.lang.Nullable; + /** * JSP tag for collecting arguments and passing them to an {@link ArgumentAware} * ancestor in the tag hierarchy. @@ -33,6 +35,7 @@ import javax.servlet.jsp.tagext.BodyTagSupport; @SuppressWarnings("serial") public class ArgumentTag extends BodyTagSupport { + @Nullable private Object value; private boolean valueSet; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindErrorsTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindErrorsTag.java index 666a334b30..4526b0bca4 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindErrorsTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindErrorsTag.java @@ -20,6 +20,7 @@ import javax.servlet.ServletException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; +import org.springframework.lang.Nullable; import org.springframework.validation.Errors; /** @@ -38,8 +39,9 @@ public class BindErrorsTag extends HtmlEscapingAwareTag { public static final String ERRORS_VARIABLE_NAME = "errors"; - private String name; + private String name = ""; + @Nullable private Errors errors; @@ -80,6 +82,7 @@ public class BindErrorsTag extends HtmlEscapingAwareTag { * Retrieve the Errors instance that this tag is currently bound to. *

Intended for cooperating nesting tags. */ + @Nullable public final Errors getErrors() { return this.errors; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindTag.java index 5481cc53e3..310dede393 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/BindTag.java @@ -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. @@ -17,11 +17,11 @@ package org.springframework.web.servlet.tags; import java.beans.PropertyEditor; - import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.PageContext; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.validation.Errors; import org.springframework.web.servlet.support.BindStatus; @@ -55,14 +55,17 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag { public static final String STATUS_VARIABLE_NAME = "status"; - private String path; + private String path = ""; private boolean ignoreNestedPath = false; + @Nullable private BindStatus status; + @Nullable private Object previousPageStatus; + @Nullable private Object previousRequestStatus; @@ -150,6 +153,14 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag { } + /** + * Return the current BindStatus. + */ + private BindStatus getStatus() { + Assert.state(this.status != null, "No current BindStatus"); + return this.status; + } + /** * Retrieve the property that this tag is currently bound to, * or {@code null} if bound to an object rather than a specific property. @@ -159,7 +170,7 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag { */ @Nullable public final String getProperty() { - return this.status.getExpression(); + return getStatus().getExpression(); } /** @@ -169,12 +180,12 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag { */ @Nullable public final Errors getErrors() { - return this.status.getErrors(); + return getStatus().getErrors(); } @Override public final PropertyEditor getEditor() { - return this.status.getEditor(); + return getStatus().getEditor(); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/EvalTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/EvalTag.java index 5e1ed04b95..b1abd2db50 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/EvalTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/EvalTag.java @@ -59,8 +59,10 @@ public class EvalTag extends HtmlEscapingAwareTag { private final ExpressionParser expressionParser = new SpelExpressionParser(); + @Nullable private Expression expression; + @Nullable private String var; private int scope = PageContext.PAGE_SCOPE; @@ -114,12 +116,13 @@ public class EvalTag extends HtmlEscapingAwareTag { this.pageContext.setAttribute(EVALUATION_CONTEXT_PAGE_ATTRIBUTE, evaluationContext); } if (this.var != null) { - Object result = this.expression.getValue(evaluationContext); + Object result = (this.expression != null ? this.expression.getValue(evaluationContext) : null); this.pageContext.setAttribute(this.var, result, this.scope); } else { try { - String result = this.expression.getValue(evaluationContext, String.class); + String result = (this.expression != null ? + this.expression.getValue(evaluationContext, String.class) : null); result = ObjectUtils.getDisplayString(result); result = htmlEscape(result); result = (this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(result) : result); @@ -156,6 +159,7 @@ public class EvalTag extends HtmlEscapingAwareTag { private final PageContext pageContext; + @Nullable private final javax.servlet.jsp.el.VariableResolver variableResolver; public JspPropertyAccessor(PageContext pageContext) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/HtmlEscapingAwareTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/HtmlEscapingAwareTag.java index 18d1014a87..7c261a4270 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/HtmlEscapingAwareTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/HtmlEscapingAwareTag.java @@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags; import javax.servlet.jsp.JspException; +import org.springframework.lang.Nullable; import org.springframework.web.util.HtmlUtils; /** @@ -40,6 +41,7 @@ import org.springframework.web.util.HtmlUtils; @SuppressWarnings("serial") public abstract class HtmlEscapingAwareTag extends RequestContextAwareTag { + @Nullable private Boolean htmlEscape; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java index 6d39c8f13c..bbdbf5f69b 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java @@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags; import java.io.IOException; import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import javax.servlet.jsp.JspException; @@ -65,18 +66,23 @@ public class MessageTag extends HtmlEscapingAwareTag implements ArgumentAware { public static final String DEFAULT_ARGUMENT_SEPARATOR = ","; + @Nullable private MessageSourceResolvable message; + @Nullable private String code; + @Nullable private Object arguments; private String argumentSeparator = DEFAULT_ARGUMENT_SEPARATOR; - private List nestedArguments; + private List nestedArguments = Collections.emptyList(); + @Nullable private String text; + @Nullable private String var; private String scope = TagUtils.SCOPE_PAGE; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/NestedPathTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/NestedPathTag.java index 0484e69aca..28dfbf3848 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/NestedPathTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/NestedPathTag.java @@ -49,9 +49,11 @@ public class NestedPathTag extends TagSupport implements TryCatchFinally { public static final String NESTED_PATH_VARIABLE_NAME = "nestedPath"; + @Nullable private String path; /** Caching a previous nested path, so that it may be reset */ + @Nullable private String previousNestedPath; @@ -74,6 +76,7 @@ public class NestedPathTag extends TagSupport implements TryCatchFinally { /** * Return the path that this tag applies to. */ + @Nullable public String getPath() { return this.path; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/Param.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/Param.java index 206190a6a5..934089677d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/Param.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/Param.java @@ -31,8 +31,10 @@ import org.springframework.lang.Nullable; */ public class Param { + @Nullable private String name; + @Nullable private String value; @@ -46,6 +48,7 @@ public class Param { /** * Return the raw parameter name. */ + @Nullable public String getName() { return this.name; } @@ -53,7 +56,7 @@ public class Param { /** * Set the raw value of the parameter */ - public void setValue(String value) { + public void setValue(@Nullable String value) { this.value = value; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ParamTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ParamTag.java index ea5e3dc39a..b8c8370675 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ParamTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ParamTag.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,6 +19,8 @@ package org.springframework.web.servlet.tags; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; +import org.springframework.lang.Nullable; + /** * JSP tag for collecting name-value parameters and passing them to a * {@link ParamAware} ancestor in the tag hierarchy. @@ -34,8 +36,9 @@ import javax.servlet.jsp.tagext.BodyTagSupport; @SuppressWarnings("serial") public class ParamTag extends BodyTagSupport { - private String name; + private String name = ""; + @Nullable private String value; private boolean valueSet; @@ -83,7 +86,7 @@ public class ParamTag extends BodyTagSupport { @Override public void release() { super.release(); - this.name = null; + this.name = ""; this.value = null; this.valueSet = false; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.java index 7105bc71c0..69a17f0b07 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.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. @@ -24,6 +24,8 @@ import javax.servlet.jsp.tagext.TryCatchFinally; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.web.servlet.support.JspAwareRequestContext; import org.springframework.web.servlet.support.RequestContext; @@ -60,6 +62,7 @@ public abstract class RequestContextAwareTag extends TagSupport implements TryCa protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private RequestContext requestContext; @@ -79,11 +82,7 @@ public abstract class RequestContextAwareTag extends TagSupport implements TryCa } return doStartTagInternal(); } - catch (JspException ex) { - logger.error(ex.getMessage(), ex); - throw ex; - } - catch (RuntimeException ex) { + catch (JspException | RuntimeException ex) { logger.error(ex.getMessage(), ex); throw ex; } @@ -97,6 +96,7 @@ public abstract class RequestContextAwareTag extends TagSupport implements TryCa * Return the current RequestContext. */ protected final RequestContext getRequestContext() { + Assert.state(this.requestContext != null, "No current RequestContext"); return this.requestContext; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/TransformTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/TransformTag.java index 6cb543791e..7e752f47f6 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/TransformTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/TransformTag.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. @@ -21,6 +21,7 @@ import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport; +import org.springframework.lang.Nullable; import org.springframework.web.util.TagUtils; /** @@ -41,9 +42,11 @@ import org.springframework.web.util.TagUtils; public class TransformTag extends HtmlEscapingAwareTag { /** the value to transform using the appropriate property editor */ + @Nullable private Object value; /** the variable to put the result in */ + @Nullable private String var; /** the scope of the variable the result will be put in */ diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/UrlTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/UrlTag.java index d80d5017ef..150c0ba2d6 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/UrlTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/UrlTag.java @@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -28,6 +29,8 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.servlet.support.RequestDataValueProcessor; import org.springframework.web.util.JavaScriptUtils; @@ -82,16 +85,20 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware { private static final String URL_TYPE_ABSOLUTE = "://"; - private List params; + private List params = Collections.emptyList(); - private Set templateParams; + private Set templateParams = Collections.emptySet(); + @Nullable private UrlType type; + @Nullable private String value; + @Nullable private String context; + @Nullable private String var; private int scope = PageContext.PAGE_SCOPE; @@ -198,9 +205,11 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware { * @return the URL value as a String * @throws JspException */ - private String createUrl() throws JspException { + String createUrl() throws JspException { + Assert.state(this.value != null, "No value set"); HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); HttpServletResponse response = (HttpServletResponse) pageContext.getResponse(); + StringBuilder url = new StringBuilder(); if (this.type == UrlType.CONTEXT_RELATIVE) { // add application context to url @@ -231,7 +240,7 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware { // HTML and/or JavaScript escape, if demanded. urlStr = htmlEscape(urlStr); - urlStr = this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(urlStr) : urlStr; + urlStr = (this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(urlStr) : urlStr); return urlStr; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractUrlBasedView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractUrlBasedView.java index 36d94df02b..f6b2878bba 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractUrlBasedView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractUrlBasedView.java @@ -30,6 +30,7 @@ import org.springframework.lang.Nullable; */ public abstract class AbstractUrlBasedView extends AbstractView implements InitializingBean { + @Nullable private String url; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java index 7dcaff51fd..637baec0a9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java @@ -69,10 +69,10 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 4096; - private String beanName; - + @Nullable private String contentType = DEFAULT_CONTENT_TYPE; + @Nullable private String requestContextAttribute; private final Map staticAttributes = new LinkedHashMap<>(); @@ -81,26 +81,12 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement private boolean exposeContextBeansAsAttributes = false; - private Set exposedContextBeanNames; - - - /** - * Set the view's name. Helpful for traceability. - *

Framework code must call this when constructing views. - */ - @Override - public void setBeanName(String beanName) { - this.beanName = beanName; - } - - /** - * Return the view's name. Should never be {@code null}, - * if the view was correctly configured. - */ @Nullable - public String getBeanName() { - return this.beanName; - } + private Set exposedContextBeanNames; + @Nullable + private String beanName; + + /** * Set the content type for this view. @@ -287,6 +273,24 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement this.exposedContextBeanNames = new HashSet<>(Arrays.asList(exposedContextBeanNames)); } + /** + * Set the view's name. Helpful for traceability. + *

Framework code must call this when constructing views. + */ + @Override + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + /** + * Return the view's name. Should never be {@code null}, + * if the view was correctly configured. + */ + @Nullable + public String getBeanName() { + return this.beanName; + } + /** * Prepares the view given the specified model, merging it with static diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java index a6f0bfea98..b776c72a91 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java @@ -88,27 +88,21 @@ import org.springframework.web.servlet.ViewResolver; public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean { - private int order = Ordered.HIGHEST_PRECEDENCE; - + @Nullable private ContentNegotiationManager contentNegotiationManager; private final ContentNegotiationManagerFactoryBean cnmFactoryBean = new ContentNegotiationManagerFactoryBean(); private boolean useNotAcceptableStatusCode = false; + @Nullable private List defaultViews; + @Nullable private List viewResolvers; + private int order = Ordered.HIGHEST_PRECEDENCE; - public void setOrder(int order) { - this.order = order; - } - - @Override - public int getOrder() { - return this.order; - } /** * Set the {@link ContentNegotiationManager} to use to determine requested media types. @@ -124,6 +118,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport * Return the {@link ContentNegotiationManager} to use to determine requested media types. * @since 4.1.9 */ + @Nullable public ContentNegotiationManager getContentNegotiationManager() { return this.contentNegotiationManager; } @@ -157,7 +152,8 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport } public List getDefaultViews() { - return Collections.unmodifiableList(this.defaultViews); + return (this.defaultViews != null ? Collections.unmodifiableList(this.defaultViews) : + Collections.emptyList()); } /** @@ -169,7 +165,17 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport } public List getViewResolvers() { - return Collections.unmodifiableList(this.viewResolvers); + return (this.viewResolvers != null ? Collections.unmodifiableList(this.viewResolvers) : + Collections.emptyList()); + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return this.order; } @@ -243,6 +249,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport */ @Nullable protected List getMediaTypes(HttpServletRequest request) { + Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set"); try { ServletWebRequest webRequest = new ServletWebRequest(request); @@ -297,18 +304,21 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport throws Exception { List candidateViews = new ArrayList<>(); - for (ViewResolver viewResolver : this.viewResolvers) { - View view = viewResolver.resolveViewName(viewName, locale); - if (view != null) { - candidateViews.add(view); - } - for (MediaType requestedMediaType : requestedMediaTypes) { - List extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType); - for (String extension : extensions) { - String viewNameWithExtension = viewName + '.' + extension; - view = viewResolver.resolveViewName(viewNameWithExtension, locale); - if (view != null) { - candidateViews.add(view); + if (this.viewResolvers != null) { + Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set"); + for (ViewResolver viewResolver : this.viewResolvers) { + View view = viewResolver.resolveViewName(viewName, locale); + if (view != null) { + candidateViews.add(view); + } + for (MediaType requestedMediaType : requestedMediaTypes) { + List extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType); + for (String extension : extensions) { + String viewNameWithExtension = viewName + '.' + extension; + view = viewResolver.resolveViewName(viewNameWithExtension, locale); + if (view != null) { + candidateViews.add(view); + } } } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java index 13a7085053..244dfed67a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.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. @@ -16,6 +16,7 @@ package org.springframework.web.servlet.view; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -50,6 +51,7 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver { private static final boolean jstlPresent = ClassUtils.isPresent( "javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader()); + @Nullable private Boolean alwaysInclude; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/JstlView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/JstlView.java index 7906b33f04..76e8834ebd 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/JstlView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/JstlView.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. @@ -20,6 +20,7 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import org.springframework.context.MessageSource; +import org.springframework.lang.Nullable; import org.springframework.web.servlet.support.JstlUtils; import org.springframework.web.servlet.support.RequestContext; @@ -76,6 +77,7 @@ import org.springframework.web.servlet.support.RequestContext; */ public class JstlView extends InternalResourceView { + @Nullable private MessageSource messageSource; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java index e38e200ab7..8894f7d686 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java @@ -94,14 +94,17 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { private boolean exposeModelAttributes = true; + @Nullable private String encodingScheme; + @Nullable private HttpStatus statusCode; private boolean expandUriTemplateVariables = true; private boolean propagateQueryParams = false; + @Nullable private String[] hosts; @@ -270,6 +273,7 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { * Return the configured application hosts. * @since 4.3 */ + @Nullable public String[] getHosts() { return this.hosts; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ResourceBundleViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ResourceBundleViewResolver.java index 7593aaf615..02fa9c7cd2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ResourceBundleViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/ResourceBundleViewResolver.java @@ -32,6 +32,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; +import org.springframework.lang.Nullable; import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.servlet.View; @@ -72,17 +73,17 @@ public class ResourceBundleViewResolver extends AbstractCachingViewResolver private ClassLoader bundleClassLoader = Thread.currentThread().getContextClassLoader(); + @Nullable private String defaultParentView; + @Nullable private Locale[] localesToInitialize; /* Locale -> BeanFactory */ - private final Map localeCache = - new HashMap<>(); + private final Map localeCache = new HashMap<>(); /* List of ResourceBundle -> BeanFactory */ - private final Map, ConfigurableApplicationContext> bundleCache = - new HashMap<>(); + private final Map, ConfigurableApplicationContext> bundleCache = new HashMap<>(); public void setOrder(int order) { 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 4b683bcd4d..f1dd214bad 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 @@ -102,31 +102,39 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements public static final String FORWARD_URL_PREFIX = "forward:"; + @Nullable private Class viewClass; private String prefix = ""; private String suffix = ""; + @Nullable private String contentType; private boolean redirectContextRelative = true; private boolean redirectHttp10Compatible = true; + @Nullable private String[] redirectHosts; + @Nullable private String requestContextAttribute; /** Map of static attributes, keyed by attribute name (String) */ private final Map staticAttributes = new HashMap<>(); + @Nullable private Boolean exposePathVariables; + @Nullable private Boolean exposeContextBeansAsAttributes; + @Nullable private String[] exposedContextBeanNames; + @Nullable private String[] viewNames; private int order = Integer.MAX_VALUE; @@ -276,6 +284,7 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements * Return the configured application hosts for redirect purposes. * @since 4.3 */ + @Nullable public String[] getRedirectHosts() { return this.redirectHosts; } @@ -467,7 +476,10 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); - view.setHosts(getRedirectHosts()); + String[] hosts = getRedirectHosts(); + if (hosts != null) { + view.setHosts(hosts); + } return applyLifecycleMethods(viewName, view); } // Check for special "forward:" prefix. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java index 63ad49ce39..dd4fe9b0b3 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java @@ -29,6 +29,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.servlet.View; @@ -63,8 +64,10 @@ public class XmlViewResolver extends AbstractCachingViewResolver private int order = Integer.MAX_VALUE; // default: same as non-Ordered + @Nullable private Resource location; + @Nullable private ConfigurableApplicationContext cachedFactory; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfig.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfig.java index b6a6bb7ed7..7ec7ec6565 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfig.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfig.java @@ -42,7 +42,7 @@ public interface FreeMarkerConfig { Configuration getConfiguration(); /** - * Returns the {@link TaglibFactory} used to enable JSP tags to be + * Return the {@link TaglibFactory} used to enable JSP tags to be * accessed from FreeMarker templates. */ TaglibFactory getTaglibFactory(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfigurer.java index 5a9508b663..6e0b746664 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerConfigurer.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. @@ -28,7 +28,9 @@ import freemarker.template.TemplateException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ResourceLoaderAware; +import org.springframework.lang.Nullable; import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory; +import org.springframework.util.Assert; import org.springframework.web.context.ServletContextAware; /** @@ -78,8 +80,10 @@ import org.springframework.web.context.ServletContextAware; public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory implements FreeMarkerConfig, InitializingBean, ResourceLoaderAware, ServletContextAware { + @Nullable private Configuration configuration; + @Nullable private TaglibFactory taglibFactory; @@ -133,6 +137,7 @@ public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory */ @Override public Configuration getConfiguration() { + Assert.state(this.configuration != null, "No Configuration available"); return this.configuration; } @@ -141,6 +146,7 @@ public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory */ @Override public TaglibFactory getTaglibFactory() { + Assert.state(this.taglibFactory != null, "No TaglibFactory available"); return this.taglibFactory; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java index 20abfdb8c0..2f47d9b8fd 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/freemarker/FreeMarkerView.java @@ -87,12 +87,16 @@ import org.springframework.web.servlet.view.AbstractTemplateView; */ public class FreeMarkerView extends AbstractTemplateView { + @Nullable private String encoding; + @Nullable private Configuration configuration; + @Nullable private TaglibFactory taglibFactory; + @Nullable private ServletContextHashModel servletContextHashModel; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupConfigurer.java index 08c1698b16..29232c5b5e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupConfigurer.java @@ -32,6 +32,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -87,8 +88,10 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration private String resourceLoaderPath = "classpath:"; + @Nullable private MarkupTemplateEngine templateEngine; + @Nullable private ApplicationContext applicationContext; @@ -119,7 +122,8 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration } public MarkupTemplateEngine getTemplateEngine() { - return templateEngine; + Assert.state(this.templateEngine != null, "No MarkupTemplateEngine set"); + return this.templateEngine; } @Override @@ -128,6 +132,7 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration } protected ApplicationContext getApplicationContext() { + Assert.state(this.applicationContext != null, "No ApplicationContext set"); return this.applicationContext; } @@ -209,6 +214,7 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration */ private class LocaleTemplateResolver implements TemplateResolver { + @Nullable private ClassLoader classLoader; @Override @@ -218,6 +224,7 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration @Override public URL resolveTemplate(String templatePath) throws IOException { + Assert.state(this.classLoader != null, "No template ClassLoader available"); return GroovyMarkupConfigurer.this.resolveTemplate(this.classLoader, templatePath); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java index 3a7dcce12d..b7c4ff4bbb 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java @@ -31,6 +31,7 @@ import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.servlet.view.AbstractTemplateView; import org.springframework.web.util.NestedServletException; @@ -50,6 +51,7 @@ import org.springframework.web.util.NestedServletException; */ public class GroovyMarkupView extends AbstractTemplateView { + @Nullable private MarkupTemplateEngine engine; @@ -99,6 +101,7 @@ public class GroovyMarkupView extends AbstractTemplateView { @Override public boolean checkResource(Locale locale) throws Exception { + Assert.state(this.engine != null, "No MarkupTemplateEngine set"); try { this.engine.resolveTemplate(getUrl()); } @@ -124,6 +127,7 @@ public class GroovyMarkupView extends AbstractTemplateView { * for the given view URL. */ protected Template getTemplate(String viewUrl) throws Exception { + Assert.state(this.engine != null, "No MarkupTemplateEngine set"); try { return this.engine.createTemplateByPath(viewUrl); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java index f967dfd374..6d43064e9a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.ser.FilterProvider; import org.springframework.http.converter.json.MappingJacksonValue; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.servlet.view.AbstractView; @@ -53,6 +54,7 @@ public abstract class AbstractJackson2View extends AbstractView { private JsonEncoding encoding = JsonEncoding.UTF8; + @Nullable private Boolean prettyPrint; private boolean disableCaching = true; @@ -61,7 +63,8 @@ public abstract class AbstractJackson2View extends AbstractView { protected AbstractJackson2View(ObjectMapper objectMapper, String contentType) { - setObjectMapper(objectMapper); + this.objectMapper = objectMapper; + configurePrettyPrint(); setContentType(contentType); setExposePathVariables(false); } @@ -74,7 +77,6 @@ public abstract class AbstractJackson2View extends AbstractView { * on the types to be serialized, in which case a custom-configured ObjectMapper is unnecessary. */ public void setObjectMapper(ObjectMapper objectMapper) { - Assert.notNull(objectMapper, "'objectMapper' must not be null"); this.objectMapper = objectMapper; configurePrettyPrint(); } @@ -184,8 +186,12 @@ public abstract class AbstractJackson2View extends AbstractView { FilterProvider filters = (FilterProvider) model.get(FilterProvider.class.getName()); if (serializationView != null || filters != null) { MappingJacksonValue container = new MappingJacksonValue(value); - container.setSerializationView(serializationView); - container.setFilters(filters); + if (serializationView != null) { + container.setSerializationView(serializationView); + } + if (filters != null) { + container.setFilters(filters); + } value = container; } return value; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java index 85f9d68d39..ad2b0632d6 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java @@ -78,12 +78,15 @@ public class MappingJackson2JsonView extends AbstractJackson2View { private static final Pattern CALLBACK_PARAM_PATTERN = Pattern.compile("[0-9A-Za-z_\\.]*"); + @Nullable private String jsonPrefix; + @Nullable private Set modelKeys; private boolean extractValueFromSingleKeyModel = false; + @Nullable private Set jsonpParameterNames = new LinkedHashSet<>(Arrays.asList("jsonp", "callback")); @@ -146,6 +149,7 @@ public class MappingJackson2JsonView extends AbstractJackson2View { /** * Return the attributes in the model that should be rendered by this view. */ + @Nullable public final Set getModelKeys() { return this.modelKeys; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java index 7ef8f7fdb5..a67c972571 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java @@ -41,7 +41,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.core.NamedThreadLocal; import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.lang.Nullable; import org.springframework.scripting.support.StandardScriptEvalException; import org.springframework.scripting.support.StandardScriptUtils; @@ -83,24 +82,31 @@ public class ScriptTemplateView extends AbstractUrlBasedView { new NamedThreadLocal<>("ScriptTemplateView engines"); + @Nullable private ScriptEngine engine; + @Nullable private String engineName; + @Nullable private Boolean sharedEngine; + @Nullable private String[] scripts; + @Nullable private String renderObject; + @Nullable private String renderFunction; + @Nullable private Charset charset; + @Nullable private String[] resourceLoaderPaths; - private ResourceLoader resourceLoader; - + @Nullable private volatile ScriptEngineManager scriptEngineManager; @@ -164,15 +170,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView { this.renderFunction = functionName; } - /** - * See {@link ScriptTemplateConfigurer#setContentType(String)}} documentation. - * @since 4.2.1 - */ - @Override - public void setContentType(@Nullable String contentType) { - super.setContentType(contentType); - } - /** * See {@link ScriptTemplateConfigurer#setCharset(Charset)} documentation. */ @@ -227,9 +224,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView { String resourceLoaderPath = viewConfig.getResourceLoaderPath(); setResourceLoaderPath(resourceLoaderPath == null ? DEFAULT_RESOURCE_LOADER_PATH : resourceLoaderPath); } - if (this.resourceLoader == null) { - this.resourceLoader = getApplicationContext(); - } if (this.sharedEngine == null && viewConfig.isSharedEngine() != null) { this.sharedEngine = viewConfig.isSharedEngine(); } @@ -248,11 +242,12 @@ public class ScriptTemplateView extends AbstractUrlBasedView { loadScripts(this.engine); } else { - setEngine(createEngineFromName()); + setEngine(createEngineFromName(this.engineName)); } if (this.renderFunction != null && this.engine != null) { - Assert.isInstanceOf(Invocable.class, this.engine, "ScriptEngine must implement Invocable when 'renderFunction' is specified."); + Assert.isInstanceOf(Invocable.class, this.engine, + "ScriptEngine must implement Invocable when 'renderFunction' is specified"); } } @@ -263,27 +258,31 @@ public class ScriptTemplateView extends AbstractUrlBasedView { engines = new HashMap<>(4); enginesHolder.set(engines); } + Assert.state(this.engineName != null, "No engine name specified"); Object engineKey = (!ObjectUtils.isEmpty(this.scripts) ? new EngineKey(this.engineName, this.scripts) : this.engineName); ScriptEngine engine = engines.get(engineKey); if (engine == null) { - engine = createEngineFromName(); + engine = createEngineFromName(engineName); engines.put(engineKey, engine); } return engine; } else { // Simply return the configured ScriptEngine... + Assert.state(this.engine != null, "No shared engine available"); return this.engine; } } - protected ScriptEngine createEngineFromName() { - if (this.scriptEngineManager == null) { - this.scriptEngineManager = new ScriptEngineManager(obtainApplicationContext().getClassLoader()); + protected ScriptEngine createEngineFromName(String engineName) { + ScriptEngineManager scriptEngineManager = this.scriptEngineManager; + if (scriptEngineManager == null) { + scriptEngineManager = new ScriptEngineManager(obtainApplicationContext().getClassLoader()); + this.scriptEngineManager = scriptEngineManager; } - ScriptEngine engine = StandardScriptUtils.retrieveEngineByName(this.scriptEngineManager, this.engineName); + ScriptEngine engine = StandardScriptUtils.retrieveEngineByName(scriptEngineManager, engineName); loadScripts(engine); return engine; } @@ -307,10 +306,12 @@ public class ScriptTemplateView extends AbstractUrlBasedView { @Nullable protected Resource getResource(String location) { - for (String path : this.resourceLoaderPaths) { - Resource resource = this.resourceLoader.getResource(path + location); - if (resource.exists()) { - return resource; + if (this.resourceLoaderPaths != null) { + for (String path : this.resourceLoaderPaths) { + Resource resource = obtainApplicationContext().getResource(path + location); + if (resource.exists()) { + return resource; + } } } return null; @@ -341,7 +342,9 @@ public class ScriptTemplateView extends AbstractUrlBasedView { super.prepareResponse(request, response); setResponseContentType(request, response); - response.setCharacterEncoding(this.charset.name()); + if (this.charset != null) { + response.setCharacterEncoding(this.charset.name()); + } } @Override @@ -375,10 +378,10 @@ public class ScriptTemplateView extends AbstractUrlBasedView { } else if (this.renderObject != null) { Object thiz = engine.eval(this.renderObject); - html = ((Invocable)engine).invokeMethod(thiz, this.renderFunction, template, model, context); + html = ((Invocable) engine).invokeMethod(thiz, this.renderFunction, template, model, context); } else { - html = ((Invocable)engine).invokeFunction(this.renderFunction, template, model, context); + html = ((Invocable) engine).invokeFunction(this.renderFunction, template, model, context); } response.getWriter().write(String.valueOf(html)); @@ -393,7 +396,9 @@ public class ScriptTemplateView extends AbstractUrlBasedView { if (resource == null) { throw new IllegalStateException("Template resource [" + path + "] not found"); } - InputStreamReader reader = new InputStreamReader(resource.getInputStream(), this.charset); + InputStreamReader reader = (this.charset != null ? + new InputStreamReader(resource.getInputStream(), this.charset) : + new InputStreamReader(resource.getInputStream())); return FileCopyUtils.copyToString(reader); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.java index a2aec33298..a9d2e3af34 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.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. @@ -63,6 +63,8 @@ import org.springframework.beans.BeanWrapper; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.web.context.ServletContextAware; @@ -130,20 +132,25 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private TilesInitializer tilesInitializer; + @Nullable private String[] definitions; private boolean checkRefresh = false; private boolean validateDefinitions = true; + @Nullable private Class definitionsFactoryClass; + @Nullable private Class preparerFactoryClass; private boolean useMutableTilesContainer = false; + @Nullable private ServletContext servletContext; @@ -264,6 +271,7 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D */ @Override public void afterPropertiesSet() throws TilesException { + Assert.state(this.servletContext != null, "No ServletContext available"); ApplicationContext preliminaryContext = new SpringWildcardServletTilesApplicationContext(this.servletContext); if (this.tilesInitializer == null) { this.tilesInitializer = new SpringTilesInitializer(); @@ -277,7 +285,9 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D */ @Override public void destroy() throws TilesException { - this.tilesInitializer.destroy(); + if (this.tilesInitializer != null) { + this.tilesInitializer.destroy(); + } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesView.java index da4257b066..d297ca486a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesView.java @@ -32,6 +32,7 @@ import org.apache.tiles.request.render.Renderer; import org.apache.tiles.request.servlet.ServletRequest; import org.apache.tiles.request.servlet.ServletUtil; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; @@ -54,12 +55,14 @@ import org.springframework.web.servlet.view.AbstractUrlBasedView; */ public class TilesView extends AbstractUrlBasedView { + @Nullable private Renderer renderer; private boolean exposeJstlAttributes = true; private boolean alwaysInclude = false; + @Nullable private ApplicationContext applicationContext; @@ -107,17 +110,21 @@ public class TilesView extends AbstractUrlBasedView { @Override public boolean checkResource(final Locale locale) throws Exception { + Assert.state(this.renderer != null, "No Renderer set"); + HttpServletRequest servletRequest = null; RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes instanceof ServletRequestAttributes) { servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest(); } + Request request = new ServletRequest(this.applicationContext, servletRequest, null) { @Override public Locale getRequestLocale() { return locale; } }; + return this.renderer.isRenderable(getUrl(), request); } @@ -125,6 +132,8 @@ public class TilesView extends AbstractUrlBasedView { protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + Assert.state(this.renderer != null, "No Renderer set"); + exposeModelAsRequestAttributes(model, request); if (this.exposeJstlAttributes) { JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext())); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesViewResolver.java index b6e2c3b8ae..172bf5cf30 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles3/TilesViewResolver.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. @@ -18,6 +18,7 @@ package org.springframework.web.servlet.view.tiles3; import org.apache.tiles.request.render.Renderer; +import org.springframework.lang.Nullable; import org.springframework.web.servlet.view.UrlBasedViewResolver; /** @@ -32,8 +33,10 @@ import org.springframework.web.servlet.view.UrlBasedViewResolver; */ public class TilesViewResolver extends UrlBasedViewResolver { + @Nullable private Renderer renderer; + @Nullable private Boolean alwaysInclude; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MappingJackson2XmlView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MappingJackson2XmlView.java index 591564aa0e..46d7abd4a2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MappingJackson2XmlView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MappingJackson2XmlView.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.validation.BindingResult; import org.springframework.web.servlet.View; @@ -47,6 +48,7 @@ public class MappingJackson2XmlView extends AbstractJackson2View { public static final String DEFAULT_CONTENT_TYPE = "application/xml"; + @Nullable private String modelKey; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MarshallingView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MarshallingView.java index a39cd13b41..83ab402e41 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MarshallingView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xml/MarshallingView.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. @@ -18,7 +18,6 @@ package org.springframework.web.servlet.view.xml; import java.io.ByteArrayOutputStream; import java.util.Map; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.bind.JAXBElement; @@ -52,8 +51,10 @@ public class MarshallingView extends AbstractView { public static final String DEFAULT_CONTENT_TYPE = "application/xml"; + @Nullable private Marshaller marshaller; + @Nullable private String modelKey; @@ -106,6 +107,8 @@ public class MarshallingView extends AbstractView { if (toBeMarshalled == null) { throw new IllegalStateException("Unable to locate object to be marshalled in model: " + model); } + + Assert.state(this.marshaller != null, "No Marshaller set"); ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); this.marshaller.marshal(toBeMarshalled, new StreamResult(baos)); @@ -159,6 +162,7 @@ public class MarshallingView extends AbstractView { * @see Marshaller#supports(Class) */ protected boolean isEligibleForMarshalling(String modelKey, Object value) { + Assert.state(this.marshaller != null, "No Marshaller set"); Class classToCheck = value.getClass(); if (value instanceof JAXBElement) { classToCheck = ((JAXBElement) value).getDeclaredType(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltView.java index a362999034..60bf1a88d8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltView.java @@ -75,22 +75,28 @@ import org.springframework.web.util.WebUtils; */ public class XsltView extends AbstractUrlBasedView { + @Nullable private Class transformerFactoryClass; + @Nullable private String sourceKey; + @Nullable private URIResolver uriResolver; private ErrorListener errorListener = new SimpleTransformErrorListener(logger); private boolean indent = true; + @Nullable private Properties outputProperties; private boolean cacheTemplates = true; + @Nullable private TransformerFactory transformerFactory; + @Nullable private Templates cachedTemplates; @@ -215,6 +221,7 @@ public class XsltView extends AbstractUrlBasedView { * @return the TransformerFactory (never {@code null}) */ protected final TransformerFactory getTransformerFactory() { + Assert.state(this.transformerFactory != null, "No TransformerFactory available"); return this.transformerFactory; } @@ -416,7 +423,7 @@ public class XsltView extends AbstractUrlBasedView { private Templates loadTemplates() throws ApplicationContextException { Source stylesheetSource = getStylesheetSource(); try { - Templates templates = this.transformerFactory.newTemplates(stylesheetSource); + Templates templates = getTransformerFactory().newTemplates(stylesheetSource); if (logger.isDebugEnabled()) { logger.debug("Loading templates '" + templates + "'"); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltViewResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltViewResolver.java index fda12ff096..232e83d2d1 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltViewResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/xslt/XsltViewResolver.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,6 +20,7 @@ import java.util.Properties; import javax.xml.transform.ErrorListener; import javax.xml.transform.URIResolver; +import org.springframework.lang.Nullable; import org.springframework.web.servlet.view.AbstractUrlBasedView; import org.springframework.web.servlet.view.UrlBasedViewResolver; @@ -34,14 +35,18 @@ import org.springframework.web.servlet.view.UrlBasedViewResolver; */ public class XsltViewResolver extends UrlBasedViewResolver { + @Nullable private String sourceKey; + @Nullable private URIResolver uriResolver; + @Nullable private ErrorListener errorListener; private boolean indent = true; + @Nullable private Properties outputProperties; private boolean cacheTemplates = true; @@ -124,7 +129,9 @@ public class XsltViewResolver extends UrlBasedViewResolver { @Override protected AbstractUrlBasedView buildView(String viewName) throws Exception { XsltView view = (XsltView) super.buildView(viewName); - view.setSourceKey(this.sourceKey); + if (this.sourceKey != null) { + view.setSourceKey(this.sourceKey); + } if (this.uriResolver != null) { view.setUriResolver(this.uriResolver); } @@ -132,7 +139,9 @@ public class XsltViewResolver extends UrlBasedViewResolver { view.setErrorListener(this.errorListener); } view.setIndent(this.indent); - view.setOutputProperties(this.outputProperties); + if (this.outputProperties != null) { + view.setOutputProperties(this.outputProperties); + } view.setCacheTemplates(this.cacheTemplates); return view; } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/UrlTagTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/UrlTagTests.java index f65ee4c181..b53abd6486 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/UrlTagTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/UrlTagTests.java @@ -44,13 +44,15 @@ public class UrlTagTests extends AbstractTagTests { private MockPageContext context; + @Before - public void setUp() throws Exception { + public void setup() throws Exception { context = createPageContext(); tag = new UrlTag(); tag.setPageContext(context); } + @Test public void paramSupport() { assertThat(tag, instanceOf(ParamAware.class)); @@ -66,7 +68,6 @@ public class UrlTagTests extends AbstractTagTests { @Test public void doEndTag() throws JspException { tag.setValue("url/path"); - tag.doStartTag(); int action = tag.doEndTag(); @@ -77,12 +78,10 @@ public class UrlTagTests extends AbstractTagTests { public void varDefaultScope() throws JspException { tag.setValue("url/path"); tag.setVar("var"); - tag.doStartTag(); tag.doEndTag(); - assertEquals("url/path", context.getAttribute("var", - PageContext.PAGE_SCOPE)); + assertEquals("url/path", context.getAttribute("var", PageContext.PAGE_SCOPE)); } @Test @@ -90,19 +89,16 @@ public class UrlTagTests extends AbstractTagTests { tag.setValue("url/path"); tag.setVar("var"); tag.setScope("request"); - tag.doStartTag(); tag.doEndTag(); - assertEquals("url/path", context.getAttribute("var", - PageContext.REQUEST_SCOPE)); + assertEquals("url/path", context.getAttribute("var", PageContext.REQUEST_SCOPE)); } @Test public void setHtmlEscapeDefault() throws JspException { tag.setValue("url/path"); tag.setVar("var"); - tag.doStartTag(); Param param = new Param(); @@ -116,9 +112,7 @@ public class UrlTagTests extends AbstractTagTests { tag.addParam(param); tag.doEndTag(); - - assertEquals("url/path?n%20me=v%26l%3De&name=value2", context - .getAttribute("var")); + assertEquals("url/path?n%20me=v%26l%3De&name=value2", context.getAttribute("var")); } @Test @@ -140,9 +134,7 @@ public class UrlTagTests extends AbstractTagTests { tag.addParam(param); tag.doEndTag(); - - assertEquals("url/path?n%20me=v%26l%3De&name=value2", context - .getAttribute("var")); + assertEquals("url/path?n%20me=v%26l%3De&name=value2", context.getAttribute("var")); } @Test @@ -150,7 +142,6 @@ public class UrlTagTests extends AbstractTagTests { tag.setValue("url/path"); tag.setVar("var"); tag.setHtmlEscape(true); - tag.doStartTag(); Param param = new Param(); @@ -164,9 +155,7 @@ public class UrlTagTests extends AbstractTagTests { tag.addParam(param); tag.doEndTag(); - - assertEquals("url/path?n%20me=v%26l%3De&name=value2", context - .getAttribute("var")); + assertEquals("url/path?n%20me=v%26l%3De&name=value2", context.getAttribute("var")); } @Test @@ -174,7 +163,6 @@ public class UrlTagTests extends AbstractTagTests { tag.setValue("url/path"); tag.setVar("var"); tag.setJavaScriptEscape(true); - tag.doStartTag(); Param param = new Param(); @@ -188,9 +176,7 @@ public class UrlTagTests extends AbstractTagTests { tag.addParam(param); tag.doEndTag(); - - assertEquals("url\\/path?n%20me=v%26l%3De&name=value2", context - .getAttribute("var")); + assertEquals("url\\/path?n%20me=v%26l%3De&name=value2", context.getAttribute("var")); } @Test @@ -199,7 +185,6 @@ public class UrlTagTests extends AbstractTagTests { tag.setVar("var"); tag.setHtmlEscape(true); tag.setJavaScriptEscape(true); - tag.doStartTag(); Param param = new Param(); @@ -213,9 +198,7 @@ public class UrlTagTests extends AbstractTagTests { tag.addParam(param); tag.doEndTag(); - - assertEquals("url\\/path?n%20me=v%26l%3De&name=value2", context - .getAttribute("var")); + assertEquals("url\\/path?n%20me=v%26l%3De&name=value2", context.getAttribute("var")); } @Test @@ -224,7 +207,6 @@ public class UrlTagTests extends AbstractTagTests { Set usedParams = new HashSet<>(); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("", queryString); } @@ -239,13 +221,11 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("?name=value", queryString); } @Test - public void createQueryStringOneParamForExsistingQueryString() - throws JspException { + public void createQueryStringOneParamForExsistingQueryString() throws JspException { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); @@ -255,7 +235,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, false); - assertEquals("&name=value", queryString); } @@ -270,7 +249,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("?name=", queryString); } @@ -285,7 +263,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("?name", queryString); } @@ -298,11 +275,9 @@ public class UrlTagTests extends AbstractTagTests { param.setName("name"); param.setValue("value"); params.add(param); - usedParams.add("name"); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("", queryString); } @@ -322,7 +297,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("?name=value&name=value2", queryString); } @@ -342,7 +316,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("?n%20me=v%26l%3De&name=value2", queryString); } @@ -357,7 +330,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("", queryString); } @@ -372,7 +344,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String queryString = tag.createQueryString(params, usedParams, true); - assertEquals("", queryString); } @@ -381,29 +352,23 @@ public class UrlTagTests extends AbstractTagTests { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); - String uri = tag.replaceUriTemplateParams("url/path", params, - usedParams); - + String uri = tag.replaceUriTemplateParams("url/path", params, usedParams); assertEquals("url/path", uri); assertEquals(0, usedParams.size()); } @Test - public void replaceUriTemplateParamsTemplateWithoutParamMatch() - throws JspException { + public void replaceUriTemplateParamsTemplateWithoutParamMatch() throws JspException { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); - String uri = tag.replaceUriTemplateParams("url/{path}", params, - usedParams); - + String uri = tag.replaceUriTemplateParams("url/{path}", params, usedParams); assertEquals("url/{path}", uri); assertEquals(0, usedParams.size()); } @Test - public void replaceUriTemplateParamsTemplateWithParamMatch() - throws JspException { + public void replaceUriTemplateParamsTemplateWithParamMatch() throws JspException { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); @@ -412,17 +377,14 @@ public class UrlTagTests extends AbstractTagTests { param.setValue("value"); params.add(param); - String uri = tag.replaceUriTemplateParams("url/{name}", params, - usedParams); - + String uri = tag.replaceUriTemplateParams("url/{name}", params, usedParams); assertEquals("url/value", uri); assertEquals(1, usedParams.size()); assertTrue(usedParams.contains("name")); } @Test - public void replaceUriTemplateParamsTemplateWithParamMatchNamePreEncoding() - throws JspException { + public void replaceUriTemplateParamsTemplateWithParamMatchNamePreEncoding() throws JspException { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); @@ -431,17 +393,14 @@ public class UrlTagTests extends AbstractTagTests { param.setValue("value"); params.add(param); - String uri = tag.replaceUriTemplateParams("url/{n me}", params, - usedParams); - + String uri = tag.replaceUriTemplateParams("url/{n me}", params, usedParams); assertEquals("url/value", uri); assertEquals(1, usedParams.size()); assertTrue(usedParams.contains("n me")); } @Test - public void replaceUriTemplateParamsTemplateWithParamMatchValueEncoded() - throws JspException { + public void replaceUriTemplateParamsTemplateWithParamMatchValueEncoded() throws JspException { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); @@ -458,11 +417,8 @@ public class UrlTagTests extends AbstractTagTests { assertTrue(usedParams.contains("name")); } - // SPR-11401 - - @Test - public void replaceUriTemplateParamsTemplateWithPathSegment() - throws JspException { + @Test // SPR-11401 + public void replaceUriTemplateParamsTemplateWithPathSegment() throws JspException { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); @@ -479,8 +435,7 @@ public class UrlTagTests extends AbstractTagTests { } @Test - public void replaceUriTemplateParamsTemplateWithPath() - throws JspException { + public void replaceUriTemplateParamsTemplateWithPath() throws JspException { List params = new LinkedList<>(); Set usedParams = new HashSet<>(); @@ -490,7 +445,6 @@ public class UrlTagTests extends AbstractTagTests { params.add(param); String uri = tag.replaceUriTemplateParams("url/{name}", params, usedParams); - assertEquals("url/my/Id", uri); assertEquals(1, usedParams.size()); assertTrue(usedParams.contains("name")); @@ -499,89 +453,71 @@ public class UrlTagTests extends AbstractTagTests { @Test public void createUrlRemoteServer() throws JspException { tag.setValue("http://www.springframework.org/"); - tag.doStartTag(); - // String uri = tag.createUrl(); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("http://www.springframework.org/", uri); } @Test public void createUrlRelative() throws JspException { tag.setValue("url/path"); - tag.doStartTag(); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("url/path", uri); } @Test public void createUrlLocalContext() throws JspException { - ((MockHttpServletRequest) context.getRequest()) - .setContextPath("/app-context"); + ((MockHttpServletRequest) context.getRequest()).setContextPath("/app-context"); tag.setValue("/url/path"); - tag.doStartTag(); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("/app-context/url/path", uri); } @Test public void createUrlRemoteContext() throws JspException { - ((MockHttpServletRequest) context.getRequest()) - .setContextPath("/app-context"); + ((MockHttpServletRequest) context.getRequest()).setContextPath("/app-context"); tag.setValue("/url/path"); tag.setContext("some-other-context"); - tag.doStartTag(); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("/some-other-context/url/path", uri); } @Test public void createUrlRemoteContextWithSlash() throws JspException { - ((MockHttpServletRequest) context.getRequest()) - .setContextPath("/app-context"); + ((MockHttpServletRequest) context.getRequest()).setContextPath("/app-context"); tag.setValue("/url/path"); tag.setContext("/some-other-context"); - tag.doStartTag(); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("/some-other-context/url/path", uri); } @Test public void createUrlRemoteContextSingleSlash() throws JspException { - ((MockHttpServletRequest) context.getRequest()) - .setContextPath("/app-context"); + ((MockHttpServletRequest) context.getRequest()).setContextPath("/app-context"); tag.setValue("/url/path"); tag.setContext("/"); - tag.doStartTag(); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("/url/path", uri); } @Test public void createUrlWithParams() throws JspException { tag.setValue("url/path"); - tag.doStartTag(); Param param = new Param(); @@ -594,15 +530,13 @@ public class UrlTagTests extends AbstractTagTests { param.setValue("v lue"); tag.addParam(param); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("url/path?name=value&n%20me=v%20lue", uri); } @Test public void createUrlWithTemplateParams() throws JspException { tag.setValue("url/{name}"); - tag.doStartTag(); Param param = new Param(); @@ -615,16 +549,13 @@ public class UrlTagTests extends AbstractTagTests { param.setValue("v lue"); tag.addParam(param); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("url/value?n%20me=v%20lue", uri); } @Test - public void createUrlWithParamAndExsistingQueryString() - throws JspException { + public void createUrlWithParamAndExistingQueryString() throws JspException { tag.setValue("url/path?foo=bar"); - tag.doStartTag(); Param param = new Param(); @@ -632,29 +563,8 @@ public class UrlTagTests extends AbstractTagTests { param.setValue("value"); tag.addParam(param); - String uri = invokeCreateUrl(tag); - + String uri = tag.createUrl(); assertEquals("url/path?foo=bar&name=value", uri); } - @Test - public void jspWriterOutput() { - // TODO assert that the output to the JspWriter is the expected output - } - - @Test - public void servletRepsonseEncodeUrl() { - // TODO assert that HttpServletResponse.encodeURL(String) is invoked for - // non absolute urls - } - - // support methods - - private String invokeCreateUrl(UrlTag tag) { - Method createUrl = ReflectionUtils.findMethod(tag.getClass(), - "createUrl"); - ReflectionUtils.makeAccessible(createUrl); - return (String) ReflectionUtils.invokeMethod(createUrl, tag); - } - } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerMacroTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerMacroTests.java index 308e25185e..6131af4ccb 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerMacroTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerMacroTests.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,6 +20,7 @@ import java.io.FileWriter; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; @@ -27,7 +28,6 @@ import freemarker.template.Configuration; import freemarker.template.SimpleHash; import freemarker.template.Template; import freemarker.template.TemplateException; - import org.junit.Before; import org.junit.Test; @@ -69,12 +69,14 @@ public class FreeMarkerMacroTests { @Before public void setUp() throws Exception { + ServletContext sc = new MockServletContext(); wac = new StaticWebApplicationContext(); - wac.setServletContext(new MockServletContext()); + wac.setServletContext(sc); // final Template expectedTemplate = new Template(); fc = new FreeMarkerConfigurer(); fc.setTemplateLoaderPaths("classpath:/", "file://" + System.getProperty("java.io.tmpdir")); + fc.setServletContext(sc); fc.afterPropertiesSet(); wac.getDefaultListableBeanFactory().registerSingleton("freeMarkerConfigurer", fc); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerViewTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerViewTests.java index 823c5cd7ac..d07f940c3a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerViewTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerViewTests.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,10 @@ import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletResponse; +import freemarker.ext.servlet.AllHttpScopesHashModel; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -42,11 +46,6 @@ import org.springframework.web.servlet.view.AbstractView; import org.springframework.web.servlet.view.InternalResourceView; import org.springframework.web.servlet.view.RedirectView; -import freemarker.ext.servlet.AllHttpScopesHashModel; -import freemarker.template.Configuration; -import freemarker.template.Template; -import freemarker.template.TemplateException; - import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; @@ -61,6 +60,7 @@ public class FreeMarkerViewTests { @Rule public final ExpectedException exception = ExpectedException.none(); + @Test public void noFreeMarkerConfig() throws Exception { FreeMarkerView fv = new FreeMarkerView(); @@ -95,6 +95,7 @@ public class FreeMarkerViewTests { Map configs = new HashMap<>(); FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setConfiguration(new TestConfiguration()); + configurer.setServletContext(sc); configs.put("configurer", configurer); given(wac.getBeansOfType(FreeMarkerConfig.class, true, false)).willReturn(configs); given(wac.getServletContext()).willReturn(sc); @@ -125,6 +126,7 @@ public class FreeMarkerViewTests { Map configs = new HashMap<>(); FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setConfiguration(new TestConfiguration()); + configurer.setServletContext(sc); configs.put("configurer", configurer); given(wac.getBeansOfType(FreeMarkerConfig.class, true, false)).willReturn(configs); given(wac.getServletContext()).willReturn(sc); @@ -148,11 +150,14 @@ public class FreeMarkerViewTests { @Test public void freeMarkerViewResolver() throws Exception { + MockServletContext sc = new MockServletContext(); + FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setConfiguration(new TestConfiguration()); + configurer.setServletContext(sc); StaticWebApplicationContext wac = new StaticWebApplicationContext(); - wac.setServletContext(new MockServletContext()); + wac.setServletContext(sc); wac.getBeanFactory().registerSingleton("configurer", configurer); wac.refresh(); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/CloseStatus.java b/spring-websocket/src/main/java/org/springframework/web/socket/CloseStatus.java index acfae470c6..20e65d81a3 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/CloseStatus.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/CloseStatus.java @@ -145,6 +145,7 @@ public final class CloseStatus { private final int code; + @Nullable private final String reason; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.java b/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.java index ca139f2438..e9a7e3cbfd 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.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. @@ -18,6 +18,8 @@ package org.springframework.web.socket; import java.nio.charset.StandardCharsets; +import org.springframework.lang.Nullable; + /** * A text WebSocket message. * @@ -26,6 +28,7 @@ import java.nio.charset.StandardCharsets; */ public final class TextMessage extends AbstractWebSocketMessage { + @Nullable private final byte[] bytes; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java index d548671925..77e5984cb6 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java @@ -79,6 +79,7 @@ public interface WebSocketSession extends Closeable { /** * Return the address of the remote client. */ + @Nullable InetSocketAddress getRemoteAddress(); /** diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/adapter/AbstractWebSocketSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/adapter/AbstractWebSocketSession.java index ef2297457e..b5fa19b6f6 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/adapter/AbstractWebSocketSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/adapter/AbstractWebSocketSession.java @@ -45,6 +45,7 @@ public abstract class AbstractWebSocketSession implements NativeWebSocketSess private final Map attributes = new ConcurrentHashMap<>(); + @Nullable private T nativeSession; @@ -67,6 +68,7 @@ public abstract class AbstractWebSocketSession implements NativeWebSocketSess @Override public T getNativeSession() { + Assert.state(this.nativeSession != null, "WebSocket session not yet initialized"); return this.nativeSession; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/adapter/jetty/JettyWebSocketSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/adapter/jetty/JettyWebSocketSession.java index 4c569f0f2a..d437015588 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/adapter/jetty/JettyWebSocketSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/adapter/jetty/JettyWebSocketSession.java @@ -32,6 +32,7 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; import org.springframework.http.HttpHeaders; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.socket.BinaryMessage; @@ -54,16 +55,22 @@ import org.springframework.web.socket.adapter.AbstractWebSocketSession; */ public class JettyWebSocketSession extends AbstractWebSocketSession { + @Nullable private String id; + @Nullable private URI uri; + @Nullable private HttpHeaders headers; + @Nullable private String acceptedProtocol; + @Nullable private List extensions; + @Nullable private Principal user; @@ -90,19 +97,19 @@ public class JettyWebSocketSession extends AbstractWebSocketSession { @Override public String getId() { - checkNativeSessionInitialized(); + Assert.state(this.id != null, "WebSocket session is not yet initialized"); return this.id; } @Override public URI getUri() { - checkNativeSessionInitialized(); + Assert.state(this.uri != null, "WebSocket session is not yet initialized"); return this.uri; } @Override public HttpHeaders getHandshakeHeaders() { - checkNativeSessionInitialized(); + Assert.state(this.headers != null, "WebSocket session is not yet initialized"); return this.headers; } @@ -114,7 +121,7 @@ public class JettyWebSocketSession extends AbstractWebSocketSession { @Override public List getExtensions() { - checkNativeSessionInitialized(); + Assert.state(this.extensions != null, "WebSocket session is not yet initialized"); return this.extensions; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/adapter/standard/StandardWebSocketSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/adapter/standard/StandardWebSocketSession.java index fc3dd5ea20..dbd4143522 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/adapter/standard/StandardWebSocketSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/adapter/standard/StandardWebSocketSession.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; - import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.Extension; @@ -32,6 +31,7 @@ import javax.websocket.Session; import org.springframework.http.HttpHeaders; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.socket.BinaryMessage; import org.springframework.web.socket.CloseStatus; @@ -50,20 +50,27 @@ import org.springframework.web.socket.adapter.AbstractWebSocketSession; */ public class StandardWebSocketSession extends AbstractWebSocketSession { + @Nullable private String id; + @Nullable private URI uri; private final HttpHeaders handshakeHeaders; + @Nullable private String acceptedProtocol; + @Nullable private List extensions; + @Nullable private Principal user; + @Nullable private final InetSocketAddress localAddress; + @Nullable private final InetSocketAddress remoteAddress; @@ -88,7 +95,7 @@ public class StandardWebSocketSession extends AbstractWebSocketSession * @param localAddress the address on which the request was received * @param remoteAddress the address of the remote client * @param user the user associated with the session; if {@code null} we'll - * fallback on the user available in the underlying WebSocket session + * fallback on the user available in the underlying WebSocket session */ public StandardWebSocketSession(@Nullable HttpHeaders headers, @Nullable Map attributes, @Nullable InetSocketAddress localAddress, @Nullable InetSocketAddress remoteAddress, @@ -105,13 +112,13 @@ public class StandardWebSocketSession extends AbstractWebSocketSession @Override public String getId() { - checkNativeSessionInitialized(); + Assert.state(this.id != null, "WebSocket session is not yet initialized"); return this.id; } @Override public URI getUri() { - checkNativeSessionInitialized(); + Assert.state(this.uri != null, "WebSocket session is not yet initialized"); return this.uri; } @@ -128,7 +135,7 @@ public class StandardWebSocketSession extends AbstractWebSocketSession @Override public List getExtensions() { - checkNativeSessionInitialized(); + Assert.state(this.extensions != null, "WebSocket session is not yet initialized"); return this.extensions; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java index 26589980d4..69ad60de18 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java @@ -43,6 +43,7 @@ public class WebSocketConnectionManager extends ConnectionManagerSupport { private final WebSocketHandler webSocketHandler; + @Nullable private WebSocketSession webSocketSession; private WebSocketHttpHeaders headers = new WebSocketHttpHeaders(); @@ -140,7 +141,7 @@ public class WebSocketConnectionManager extends ConnectionManagerSupport { future.addCallback(new ListenableFutureCallback() { @Override - public void onSuccess(WebSocketSession result) { + public void onSuccess(@Nullable WebSocketSession result) { webSocketSession = result; logger.info("Successfully connected"); } @@ -153,7 +154,9 @@ public class WebSocketConnectionManager extends ConnectionManagerSupport { @Override protected void closeConnection() throws Exception { - this.webSocketSession.close(); + if (this.webSocketSession != null) { + this.webSocketSession.close(); + } } @Override diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/jetty/JettyWebSocketClient.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/jetty/JettyWebSocketClient.java index 251c5e35a5..f7cbd12371 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/jetty/JettyWebSocketClient.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/jetty/JettyWebSocketClient.java @@ -63,6 +63,7 @@ public class JettyWebSocketClient extends AbstractWebSocketClient implements Lif private final Object lifecycleMonitor = new Object(); + @Nullable private AsyncListenableTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); @@ -85,9 +86,8 @@ public class JettyWebSocketClient extends AbstractWebSocketClient implements Lif /** * Set an {@link AsyncListenableTaskExecutor} to use when opening connections. - * If this property is set to {@code null}, calls to any of the + * If this property is set to {@code null}, calls to any of the * {@code doHandshake} methods will block until the connection is established. - * *

By default an instance of {@code SimpleAsyncTaskExecutor} is used. */ public void setTaskExecutor(@Nullable AsyncListenableTaskExecutor taskExecutor) { @@ -97,6 +97,7 @@ public class JettyWebSocketClient extends AbstractWebSocketClient implements Lif /** * Return the configured {@link TaskExecutor}. */ + @Nullable public AsyncListenableTaskExecutor getTaskExecutor() { return this.taskExecutor; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java index 1307b8236a..97d70fc910 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.socket.client.ConnectionManagerSupport; import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; @@ -41,27 +42,30 @@ import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; */ public class AnnotatedEndpointConnectionManager extends ConnectionManagerSupport implements BeanFactoryAware { + @Nullable private final Object endpoint; + @Nullable private final BeanCreatingHandlerProvider endpointProvider; private WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer(); private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("AnnotatedEndpointConnectionManager-"); + @Nullable private volatile Session session; public AnnotatedEndpointConnectionManager(Object endpoint, String uriTemplate, Object... uriVariables) { super(uriTemplate, uriVariables); - this.endpointProvider = null; this.endpoint = endpoint; + this.endpointProvider = null; } public AnnotatedEndpointConnectionManager(Class endpointClass, String uriTemplate, Object... uriVariables) { super(uriTemplate, uriVariables); - this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); this.endpoint = null; + this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); } @@ -104,7 +108,11 @@ public class AnnotatedEndpointConnectionManager extends ConnectionManagerSupport if (logger.isInfoEnabled()) { logger.info("Connecting to WebSocket at " + getUri()); } - Object endpointToUse = (endpoint != null) ? endpoint : endpointProvider.getHandler(); + Object endpointToUse = endpoint; + if (endpointToUse == null) { + Assert.state(endpointProvider != null, "No endpoint set"); + endpointToUse = endpointProvider.getHandler(); + } session = webSocketContainer.connectToServer(endpointToUse, getUri()); logger.info("Successfully connected to WebSocket"); } @@ -117,8 +125,9 @@ public class AnnotatedEndpointConnectionManager extends ConnectionManagerSupport @Override protected void closeConnection() throws Exception { try { - if (isConnected()) { - this.session.close(); + Session session = this.session; + if (session != null && session.isOpen()) { + session.close(); } } finally { @@ -128,7 +137,8 @@ public class AnnotatedEndpointConnectionManager extends ConnectionManagerSupport @Override protected boolean isConnected() { - return (this.session != null && this.session.isOpen()); + Session session = this.session; + return (session != null && session.isOpen()); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java index 7b09653ac2..8ced5ac709 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java @@ -32,6 +32,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.socket.client.ConnectionManagerSupport; import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; @@ -48,8 +49,10 @@ import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; */ public class EndpointConnectionManager extends ConnectionManagerSupport implements BeanFactoryAware { + @Nullable private final Endpoint endpoint; + @Nullable private final BeanCreatingHandlerProvider endpointProvider; private final ClientEndpointConfig.Builder configBuilder = ClientEndpointConfig.Builder.create(); @@ -58,21 +61,22 @@ public class EndpointConnectionManager extends ConnectionManagerSupport implemen private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("EndpointConnectionManager-"); + @Nullable private volatile Session session; public EndpointConnectionManager(Endpoint endpoint, String uriTemplate, Object... uriVariables) { super(uriTemplate, uriVariables); Assert.notNull(endpoint, "endpoint must not be null"); - this.endpointProvider = null; this.endpoint = endpoint; + this.endpointProvider = null; } public EndpointConnectionManager(Class endpointClass, String uriTemplate, Object... uriVars) { super(uriTemplate, uriVars); Assert.notNull(endpointClass, "endpointClass must not be null"); - this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); this.endpoint = null; + this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); } @@ -135,7 +139,11 @@ public class EndpointConnectionManager extends ConnectionManagerSupport implemen if (logger.isInfoEnabled()) { logger.info("Connecting to WebSocket at " + getUri()); } - Endpoint endpointToUse = (endpoint != null) ? endpoint : endpointProvider.getHandler(); + Endpoint endpointToUse = endpoint; + if (endpointToUse == null) { + Assert.state(endpointProvider != null, "No endpoint set"); + endpointToUse = endpointProvider.getHandler(); + } ClientEndpointConfig endpointConfig = configBuilder.build(); session = getWebSocketContainer().connectToServer(endpointToUse, endpointConfig, getUri()); logger.info("Successfully connected to WebSocket"); @@ -149,8 +157,9 @@ public class EndpointConnectionManager extends ConnectionManagerSupport implemen @Override protected void closeConnection() throws Exception { try { - if (isConnected()) { - this.session.close(); + Session session = this.session; + if (session != null && session.isOpen()) { + session.close(); } } finally { @@ -160,7 +169,8 @@ public class EndpointConnectionManager extends ConnectionManagerSupport implemen @Override protected boolean isConnected() { - return (this.session != null && this.session.isOpen()); + Session session = this.session; + return (session != null && session.isOpen()); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/StandardWebSocketClient.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/StandardWebSocketClient.java index 0ddd426622..10ba0b902e 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/StandardWebSocketClient.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/StandardWebSocketClient.java @@ -62,6 +62,7 @@ public class StandardWebSocketClient extends AbstractWebSocketClient { private final Map userProperties = new HashMap<>(); + @Nullable private AsyncListenableTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); @@ -107,7 +108,7 @@ public class StandardWebSocketClient extends AbstractWebSocketClient { /** * Set an {@link AsyncListenableTaskExecutor} to use when opening connections. - * If this property is set to {@code null}, calls to any of the + * If this property is set to {@code null}, calls to any of the * {@code doHandshake} methods will block until the connection is established. *

By default, an instance of {@code SimpleAsyncTaskExecutor} is used. */ @@ -118,6 +119,7 @@ public class StandardWebSocketClient extends AbstractWebSocketClient { /** * Return the configured {@link TaskExecutor}. */ + @Nullable public AsyncListenableTaskExecutor getTaskExecutor() { return this.taskExecutor; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/WebSocketMessageBrokerStats.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/WebSocketMessageBrokerStats.java index 885b1548af..325e07848f 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/WebSocketMessageBrokerStats.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/WebSocketMessageBrokerStats.java @@ -54,18 +54,25 @@ public class WebSocketMessageBrokerStats { private static final Log logger = LogFactory.getLog(WebSocketMessageBrokerStats.class); + @Nullable private SubProtocolWebSocketHandler webSocketHandler; + @Nullable private StompSubProtocolHandler stompSubProtocolHandler; + @Nullable private StompBrokerRelayMessageHandler stompBrokerRelay; + @Nullable private ThreadPoolExecutor inboundChannelExecutor; + @Nullable private ThreadPoolExecutor outboundChannelExecutor; + @Nullable private ScheduledThreadPoolExecutor sockJsTaskScheduler; + @Nullable private ScheduledFuture loggingTask; private long loggingPeriod = 30 * 60 * 1000; @@ -78,6 +85,9 @@ public class WebSocketMessageBrokerStats { @Nullable private StompSubProtocolHandler initStompSubProtocolHandler() { + if (this.webSocketHandler == null) { + return null; + } for (SubProtocolHandler handler : this.webSocketHandler.getProtocolHandlers()) { if (handler instanceof StompSubProtocolHandler) { return (StompSubProtocolHandler) handler; @@ -104,12 +114,12 @@ public class WebSocketMessageBrokerStats { public void setSockJsTaskScheduler(ThreadPoolTaskScheduler sockJsTaskScheduler) { this.sockJsTaskScheduler = sockJsTaskScheduler.getScheduledThreadPoolExecutor(); - this.loggingTask = initLoggingTask(1 * 60 * 1000); + this.loggingTask = initLoggingTask(60 * 1000); } @Nullable private ScheduledFuture initLoggingTask(long initialDelay) { - if (logger.isInfoEnabled() && this.loggingPeriod > 0) { + if (this.sockJsTaskScheduler != null && this.loggingPeriod > 0 && logger.isInfoEnabled()) { return this.sockJsTaskScheduler.scheduleAtFixedRate(() -> logger.info(WebSocketMessageBrokerStats.this.toString()), initialDelay, this.loggingPeriod, TimeUnit.MILLISECONDS); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/AbstractWebSocketHandlerRegistration.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/AbstractWebSocketHandlerRegistration.java index 254b9445b7..cba19355dd 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/AbstractWebSocketHandlerRegistration.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/AbstractWebSocketHandlerRegistration.java @@ -46,14 +46,17 @@ public abstract class AbstractWebSocketHandlerRegistration implements WebSock private final MultiValueMap handlerMap = new LinkedMultiValueMap<>(); + @Nullable private HandshakeHandler handshakeHandler; private final List interceptors = new ArrayList<>(); private final List allowedOrigins = new ArrayList<>(); + @Nullable private SockJsServiceRegistration sockJsServiceRegistration; + @Nullable private TaskScheduler scheduler; @@ -86,6 +89,7 @@ public abstract class AbstractWebSocketHandlerRegistration implements WebSock return this; } + @Nullable protected HandshakeHandler getHandshakeHandler() { return this.handshakeHandler; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/ServletWebSocketHandlerRegistry.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/ServletWebSocketHandlerRegistry.java index d25dce2092..99c4d04f3c 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/ServletWebSocketHandlerRegistry.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/ServletWebSocketHandlerRegistry.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. @@ -21,6 +21,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.springframework.lang.Nullable; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.MultiValueMap; @@ -42,20 +43,20 @@ public class ServletWebSocketHandlerRegistry implements WebSocketHandlerRegistry private final List registrations = new ArrayList<>(4); + @Nullable private TaskScheduler scheduler; private int order = 1; + @Nullable private UrlPathHelper urlPathHelper; public ServletWebSocketHandlerRegistry() { - this.scheduler = null; } /** * Deprecated constructor with a TaskScheduler for SockJS use. - * * @deprecated as of 5.0 a TaskScheduler is not provided upfront, not until * it is obvious that it is needed, see {@link #requiresTaskScheduler()} and * {@link #setTaskScheduler}. @@ -95,6 +96,7 @@ public class ServletWebSocketHandlerRegistry implements WebSocketHandlerRegistry this.urlPathHelper = urlPathHelper; } + @Nullable public UrlPathHelper getUrlPathHelper() { return this.urlPathHelper; } @@ -142,7 +144,7 @@ public class ServletWebSocketHandlerRegistry implements WebSocketHandlerRegistry private void updateTaskScheduler(ServletWebSocketHandlerRegistration registration) { SockJsServiceRegistration sockJsRegistration = registration.getSockJsServiceRegistration(); - if (sockJsRegistration != null && sockJsRegistration.getTaskScheduler() == null) { + if (sockJsRegistration != null && this.scheduler != null && sockJsRegistration.getTaskScheduler() == null) { sockJsRegistration.setTaskScheduler(this.scheduler); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/SockJsServiceRegistration.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/SockJsServiceRegistration.java index 4159def3a1..cbd8f5dad8 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/SockJsServiceRegistration.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/SockJsServiceRegistration.java @@ -41,20 +41,28 @@ import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsServ */ public class SockJsServiceRegistration { + @Nullable private TaskScheduler scheduler; + @Nullable private String clientLibraryUrl; + @Nullable private Integer streamBytesLimit; + @Nullable private Boolean sessionCookieNeeded; + @Nullable private Long heartbeatTime; + @Nullable private Long disconnectDelay; + @Nullable private Integer httpMessageCacheSize; + @Nullable private Boolean webSocketEnabled; private final List transportHandlers = new ArrayList<>(); @@ -65,8 +73,10 @@ public class SockJsServiceRegistration { private final List allowedOrigins = new ArrayList<>(); + @Nullable private Boolean suppressCors; + @Nullable private SockJsMessageCodec messageCodec; @@ -75,7 +85,6 @@ public class SockJsServiceRegistration { /** * Deprecated constructor with a TaskScheduler. - * * @deprecated as of 5.0 a TaskScheduler is not provided upfront, not until * it is obvious that it is needed; call {@link #getTaskScheduler()} to check * and then {@link #setTaskScheduler(TaskScheduler)} to set it before a call @@ -91,7 +100,7 @@ public class SockJsServiceRegistration { * A scheduler instance to use for scheduling SockJS heart-beats. */ public SockJsServiceRegistration setTaskScheduler(TaskScheduler scheduler) { - Assert.notNull(scheduler, "TaskScheduler is required."); + Assert.notNull(scheduler, "TaskScheduler is required"); this.scheduler = scheduler; return this; } @@ -302,9 +311,9 @@ public class SockJsServiceRegistration { } private TransportHandlingSockJsService createSockJsService() { + Assert.state(this.scheduler != null, "No TaskScheduler available"); Assert.state(this.transportHandlers.isEmpty() || this.transportHandlerOverrides.isEmpty(), "Specify either TransportHandlers or TransportHandler overrides, not both"); - return (!this.transportHandlers.isEmpty() ? new TransportHandlingSockJsService(this.scheduler, this.transportHandlers) : new DefaultSockJsService(this.scheduler, this.transportHandlerOverrides)); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompEndpointRegistry.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompEndpointRegistry.java index a29bb8324c..7545935b23 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompEndpointRegistry.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompEndpointRegistry.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.List; import java.util.Map; import org.springframework.context.ApplicationContext; +import org.springframework.lang.Nullable; import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; @@ -51,6 +52,7 @@ public class WebMvcStompEndpointRegistry implements StompEndpointRegistry { private int order = 1; + @Nullable private UrlPathHelper urlPathHelper; private final SubProtocolWebSocketHandler subProtocolWebSocketHandler; @@ -127,6 +129,7 @@ public class WebMvcStompEndpointRegistry implements StompEndpointRegistry { this.urlPathHelper = urlPathHelper; } + @Nullable protected UrlPathHelper getUrlPathHelper() { return this.urlPathHelper; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompWebSocketEndpointRegistration.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompWebSocketEndpointRegistration.java index fc4d701668..ff5b0e7d68 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompWebSocketEndpointRegistration.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompWebSocketEndpointRegistration.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.springframework.lang.Nullable; import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; @@ -35,7 +36,6 @@ import org.springframework.web.socket.sockjs.SockJsService; import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler; import org.springframework.web.socket.sockjs.transport.handler.WebSocketTransportHandler; - /** * An abstract base class for configuring STOMP over WebSocket/SockJS endpoints. * @@ -50,12 +50,14 @@ public class WebMvcStompWebSocketEndpointRegistration implements StompWebSocketE private final TaskScheduler sockJsTaskScheduler; + @Nullable private HandshakeHandler handshakeHandler; private final List interceptors = new ArrayList<>(); private final List allowedOrigins = new ArrayList<>(); + @Nullable private SockJsServiceRegistration registration; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketConfigurationSupport.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketConfigurationSupport.java index 6c16166820..0019489847 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketConfigurationSupport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketConfigurationSupport.java @@ -20,6 +20,7 @@ import java.util.Date; import java.util.concurrent.ScheduledFuture; import org.springframework.context.annotation.Bean; +import org.springframework.lang.Nullable; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @@ -33,8 +34,10 @@ import org.springframework.web.servlet.HandlerMapping; */ public class WebSocketConfigurationSupport { + @Nullable private ServletWebSocketHandlerRegistry handlerRegistry; + @Nullable private TaskScheduler scheduler; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketMessageBrokerConfigurationSupport.java b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketMessageBrokerConfigurationSupport.java index ba1195819f..6297ced988 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketMessageBrokerConfigurationSupport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketMessageBrokerConfigurationSupport.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,8 +17,10 @@ package org.springframework.web.socket.config.annotation; import org.springframework.beans.factory.config.CustomScopeConfigurer; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.lang.Nullable; import org.springframework.messaging.converter.MappingJackson2MessageConverter; import org.springframework.messaging.simp.SimpSessionScope; import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler; @@ -48,6 +50,7 @@ import org.springframework.web.socket.messaging.WebSocketAnnotationMethodMessage */ public abstract class WebSocketMessageBrokerConfigurationSupport extends AbstractMessageBrokerConfiguration { + @Nullable private WebSocketTransportRegistration transportRegistration; @@ -67,7 +70,10 @@ public abstract class WebSocketMessageBrokerConfigurationSupport extends Abstrac WebSocketHandler handler = decorateWebSocketHandler(subProtocolWebSocketHandler()); WebMvcStompEndpointRegistry registry = new WebMvcStompEndpointRegistry(handler, getTransportRegistration(), messageBrokerTaskScheduler()); - registry.setApplicationContext(getApplicationContext()); + ApplicationContext applicationContext = getApplicationContext(); + if (applicationContext != null) { + registry.setApplicationContext(applicationContext); + } registerStompEndpoints(registry); return registry.getHandlerMapping(); } @@ -126,8 +132,12 @@ public abstract class WebSocketMessageBrokerConfigurationSupport extends Abstrac protected MappingJackson2MessageConverter createJacksonConverter() { MappingJackson2MessageConverter messageConverter = super.createJacksonConverter(); // Use Jackson builder in order to have JSR-310 and Joda-Time modules registered automatically - messageConverter.setObjectMapper(Jackson2ObjectMapperBuilder.json() - .applicationContext(this.getApplicationContext()).build()); + Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); + ApplicationContext applicationContext = getApplicationContext(); + if (applicationContext != null) { + builder.applicationContext(applicationContext); + } + messageConverter.setObjectMapper(builder.build()); return messageConverter; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/handler/BeanCreatingHandlerProvider.java b/spring-websocket/src/main/java/org/springframework/web/socket/handler/BeanCreatingHandlerProvider.java index 4ef9815b51..c3f82cff9b 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/handler/BeanCreatingHandlerProvider.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/handler/BeanCreatingHandlerProvider.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,6 +20,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -34,6 +35,7 @@ public class BeanCreatingHandlerProvider implements BeanFactoryAware { private final Class handlerType; + @Nullable private AutowireCapableBeanFactory beanFactory; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/AbstractSubProtocolEvent.java b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/AbstractSubProtocolEvent.java index 9953e79063..85497792bf 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/AbstractSubProtocolEvent.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/AbstractSubProtocolEvent.java @@ -35,6 +35,7 @@ public abstract class AbstractSubProtocolEvent extends ApplicationEvent { private final Message message; + @Nullable private final Principal user; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SessionDisconnectEvent.java b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SessionDisconnectEvent.java index abaf64fc66..a735073da1 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SessionDisconnectEvent.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SessionDisconnectEvent.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. @@ -89,8 +89,7 @@ public class SessionDisconnectEvent extends AbstractSubProtocolEvent { @Override public String toString() { - return "SessionDisconnectEvent[sessionId=" + this.sessionId + ", " + - (this.status != null ? this.status.toString() : "closeStatus=null") + "]"; + return "SessionDisconnectEvent[sessionId=" + this.sessionId + ", " + this.status.toString() + "]"; } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/StompSubProtocolHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/StompSubProtocolHandler.java index e11fca8e2c..60109e544b 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/StompSubProtocolHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/StompSubProtocolHandler.java @@ -90,6 +90,7 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE private static final byte[] EMPTY_PAYLOAD = new byte[0]; + @Nullable private StompSubProtocolErrorHandler errorHandler; private int messageSizeLimit = 64 * 1024; @@ -100,12 +101,15 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE private final Map decoders = new ConcurrentHashMap<>(); + @Nullable private MessageHeaderInitializer headerInitializer; private final Map stompAuthentications = new ConcurrentHashMap<>(); + @Nullable private Boolean immutableMessageInterceptorPresent; + @Nullable private ApplicationEventPublisher eventPublisher; private final Stats stats = new Stats(); @@ -289,13 +293,13 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE } if (this.eventPublisher != null) { if (isConnect) { - publishEvent(new SessionConnectEvent(this, message, user)); + publishEvent(this.eventPublisher, new SessionConnectEvent(this, message, user)); } else if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) { - publishEvent(new SessionSubscribeEvent(this, message, user)); + publishEvent(this.eventPublisher, new SessionSubscribeEvent(this, message, user)); } else if (StompCommand.UNSUBSCRIBE.equals(headerAccessor.getCommand())) { - publishEvent(new SessionUnsubscribeEvent(this, message, user)); + publishEvent(this.eventPublisher, new SessionUnsubscribeEvent(this, message, user)); } } } @@ -372,9 +376,9 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE return false; } - private void publishEvent(ApplicationEvent event) { + private void publishEvent(ApplicationEventPublisher publisher, ApplicationEvent event) { try { - this.eventPublisher.publishEvent(event); + publisher.publishEvent(event); } catch (Throwable ex) { if (logger.isErrorEnabled()) { @@ -418,7 +422,7 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE SimpAttributes simpAttributes = new SimpAttributes(session.getId(), session.getAttributes()); SimpAttributesContextHolder.setAttributes(simpAttributes); Principal user = getUser(session); - publishEvent(new SessionConnectedEvent(this, (Message) message, user)); + publishEvent(this.eventPublisher, new SessionConnectedEvent(this, (Message) message, user)); } finally { SimpAttributesContextHolder.resetAttributes(); @@ -604,7 +608,7 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE SimpAttributesContextHolder.setAttributes(simpAttributes); if (this.eventPublisher != null) { Principal user = getUser(session); - publishEvent(new SessionDisconnectEvent(this, message, session.getId(), closeStatus, user)); + publishEvent(this.eventPublisher, new SessionDisconnectEvent(this, message, session.getId(), closeStatus, user)); } outputChannel.send(message); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java index de512e03fd..a303e4a7c7 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java @@ -89,6 +89,7 @@ public class SubProtocolWebSocketHandler private final Set protocolHandlers = new LinkedHashSet<>(); + @Nullable private SubProtocolHandler defaultProtocolHandler; private final Map sessions = new ConcurrentHashMap<>(); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractStandardUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractStandardUpgradeStrategy.java index d38d8e6319..06d3f5a907 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractStandardUpgradeStrategy.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractStandardUpgradeStrategy.java @@ -59,6 +59,7 @@ public abstract class AbstractStandardUpgradeStrategy implements RequestUpgradeS protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private volatile List extensions; @@ -84,11 +85,13 @@ public abstract class AbstractStandardUpgradeStrategy implements RequestUpgradeS @Override public List getSupportedExtensions(ServerHttpRequest request) { - if (this.extensions == null) { + List extensions = this.extensions; + if (extensions == null) { HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); - this.extensions = getInstalledExtensions(getContainer(servletRequest)); + extensions = getInstalledExtensions(getContainer(servletRequest)); + this.extensions = extensions; } - return this.extensions; + return extensions; } protected List getInstalledExtensions(WebSocketContainer container) { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointExporter.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointExporter.java index ba13883a2a..079bd49f72 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointExporter.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointExporter.java @@ -55,8 +55,10 @@ import org.springframework.web.context.support.WebApplicationObjectSupport; public class ServerEndpointExporter extends WebApplicationObjectSupport implements InitializingBean, SmartInitializingSingleton { + @Nullable private List> annotatedEndpointClasses; + @Nullable private ServerContainer serverContainer; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.java index 856614df07..01019d37cf 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.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 javax.websocket.server.ServerEndpointConfig; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; @@ -56,10 +57,12 @@ public class ServerEndpointRegistration extends ServerEndpointConfig.Configurato private final String path; - private final BeanCreatingHandlerProvider endpointProvider; - + @Nullable private final Endpoint endpoint; + @Nullable + private final BeanCreatingHandlerProvider endpointProvider; + private List> encoders = new ArrayList<>(); private List> decoders = new ArrayList<>(); @@ -71,20 +74,6 @@ public class ServerEndpointRegistration extends ServerEndpointConfig.Configurato private final Map userProperties = new HashMap<>(); - /** - * Create a new {@link ServerEndpointRegistration} instance from an - * {@code javax.websocket.Endpoint} class. - * @param path the endpoint path - * @param endpointClass the endpoint class - */ - public ServerEndpointRegistration(String path, Class endpointClass) { - Assert.hasText(path, "path must not be empty"); - Assert.notNull(endpointClass, "endpointClass must not be null"); - this.path = path; - this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); - this.endpoint = null; - } - /** * Create a new {@link ServerEndpointRegistration} instance from an * {@code javax.websocket.Endpoint} instance. @@ -95,8 +84,22 @@ public class ServerEndpointRegistration extends ServerEndpointConfig.Configurato Assert.hasText(path, "path must not be empty"); Assert.notNull(endpoint, "endpoint must not be null"); this.path = path; - this.endpointProvider = null; this.endpoint = endpoint; + this.endpointProvider = null; + } + + /** + * Create a new {@link ServerEndpointRegistration} instance from an + * {@code javax.websocket.Endpoint} class. + * @param path the endpoint path + * @param endpointClass the endpoint class + */ + public ServerEndpointRegistration(String path, Class endpointClass) { + Assert.hasText(path, "path must not be empty"); + Assert.notNull(endpointClass, "endpointClass must not be null"); + this.path = path; + this.endpoint = null; + this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); } @@ -107,11 +110,23 @@ public class ServerEndpointRegistration extends ServerEndpointConfig.Configurato @Override public Class getEndpointClass() { - return (this.endpoint != null ? this.endpoint.getClass() : this.endpointProvider.getHandlerType()); + if (this.endpoint != null) { + return this.endpoint.getClass(); + } + else { + Assert.state(this.endpointProvider != null, "No endpoint set"); + return this.endpointProvider.getHandlerType(); + } } public Endpoint getEndpoint() { - return (this.endpoint != null) ? this.endpoint : this.endpointProvider.getHandler(); + if (this.endpoint != null) { + return this.endpoint; + } + else { + Assert.state(this.endpointProvider != null, "No endpoint set"); + return this.endpointProvider.getHandler(); + } } public void setSubprotocols(List protocols) { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServletServerContainerFactoryBean.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServletServerContainerFactoryBean.java index 7fe861464f..5efff0f8bd 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServletServerContainerFactoryBean.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServletServerContainerFactoryBean.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 javax.websocket.server.ServerContainer; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.context.ServletContextAware; @@ -46,16 +47,22 @@ import org.springframework.web.context.ServletContextAware; public class ServletServerContainerFactoryBean implements FactoryBean, ServletContextAware, InitializingBean { + @Nullable private Long asyncSendTimeout; + @Nullable private Long maxSessionIdleTimeout; + @Nullable private Integer maxTextMessageBufferSize; + @Nullable private Integer maxBinaryMessageBufferSize; + @Nullable private ServletContext servletContext; + @Nullable private ServerContainer serverContainer; @@ -63,7 +70,8 @@ public class ServletServerContainerFactoryBean this.asyncSendTimeout = timeoutInMillis; } - public long getAsyncSendTimeout() { + @Nullable + public Long getAsyncSendTimeout() { return this.asyncSendTimeout; } @@ -71,6 +79,7 @@ public class ServletServerContainerFactoryBean this.maxSessionIdleTimeout = timeoutInMillis; } + @Nullable public Long getMaxSessionIdleTimeout() { return this.maxSessionIdleTimeout; } @@ -79,6 +88,7 @@ public class ServletServerContainerFactoryBean this.maxTextMessageBufferSize = bufferSize; } + @Nullable public Integer getMaxTextMessageBufferSize() { return this.maxTextMessageBufferSize; } @@ -87,6 +97,7 @@ public class ServletServerContainerFactoryBean this.maxBinaryMessageBufferSize = bufferSize; } + @Nullable public Integer getMaxBinaryMessageBufferSize() { return this.maxBinaryMessageBufferSize; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java index 25e5bd8734..405cdbd6b6 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java @@ -28,6 +28,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class SockJsException extends NestedRuntimeException { + @Nullable private final String sessionId; @@ -55,6 +56,7 @@ public class SockJsException extends NestedRuntimeException { /** * Return the SockJS session id. */ + @Nullable public String getSockJsSessionId() { return this.sessionId; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/AbstractClientSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/AbstractClientSockJsSession.java index dc0a804da0..20fc82499a 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/AbstractClientSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/AbstractClientSockJsSession.java @@ -59,8 +59,10 @@ public abstract class AbstractClientSockJsSession implements WebSocketSession { private final Map attributes = new ConcurrentHashMap<>(); + @Nullable private volatile State state = State.NEW; + @Nullable private volatile CloseStatus closeStatus; @@ -315,15 +317,19 @@ public abstract class AbstractClientSockJsSession implements WebSocketSession { } public void afterTransportClosed(@Nullable CloseStatus closeStatus) { - this.closeStatus = (this.closeStatus != null ? this.closeStatus : closeStatus); - Assert.state(this.closeStatus != null, "CloseStatus not available"); + CloseStatus cs = this.closeStatus; + if (cs == null) { + cs = closeStatus; + this.closeStatus = closeStatus; + } + Assert.state(cs != null, "CloseStatus not available"); if (logger.isDebugEnabled()) { - logger.debug("Transport closed with " + this.closeStatus + " in " + this); + logger.debug("Transport closed with " + cs + " in " + this); } this.state = State.CLOSED; try { - this.webSocketHandler.afterConnectionClosed(this, this.closeStatus); + this.webSocketHandler.afterConnectionClosed(this, cs); } catch (Throwable ex) { logger.error("WebSocketHandler.afterConnectionClosed threw an exception", ex); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java index f515b4905c..71fda88410 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java @@ -61,14 +61,17 @@ class DefaultTransportRequest implements TransportRequest { private SockJsMessageCodec codec; + @Nullable private Principal user; private long timeoutValue; + @Nullable private TaskScheduler timeoutScheduler; private final List timeoutTasks = new ArrayList<>(); + @Nullable private DefaultTransportRequest fallbackRequest; @@ -191,7 +194,7 @@ class DefaultTransportRequest implements TransportRequest { } @Override - public void onSuccess(WebSocketSession session) { + public void onSuccess(@Nullable WebSocketSession session) { if (this.handled.compareAndSet(false, true)) { this.future.set(session); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/RestTemplateXhrTransport.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/RestTemplateXhrTransport.java index 2950a21fe7..d4ab42b89f 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/RestTemplateXhrTransport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/RestTemplateXhrTransport.java @@ -165,6 +165,7 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport { private final HttpHeaders headers; + @Nullable private final String body; public XhrRequestCallback(HttpHeaders headers) { @@ -178,9 +179,7 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport { @Override public void doWithRequest(ClientHttpRequest request) throws IOException { - if (this.headers != null) { - request.getHeaders().putAll(this.headers); - } + request.getHeaders().putAll(this.headers); if (this.body != null) { StreamUtils.copy(this.body, SockJsFrame.CHARSET, request.getBody()); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsClient.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsClient.java index b1b78c2c30..57c6d4b9d8 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsClient.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsClient.java @@ -79,12 +79,15 @@ public class SockJsClient implements WebSocketClient, Lifecycle { private final List transports; + @Nullable private String[] httpHeaderNames; private InfoReceiver infoReceiver; + @Nullable private SockJsMessageCodec messageCodec; + @Nullable private TaskScheduler connectTimeoutScheduler; private volatile boolean running = false; @@ -171,7 +174,7 @@ public class SockJsClient implements WebSocketClient, Lifecycle { * Jackson2SockJsMessageCodec} is used if Jackson is on the classpath. */ public void setMessageCodec(SockJsMessageCodec messageCodec) { - Assert.notNull(messageCodec, "'messageCodec' is required"); + Assert.notNull(messageCodec, "SockJsMessageCodec is required"); this.messageCodec = messageCodec; } @@ -179,6 +182,7 @@ public class SockJsClient implements WebSocketClient, Lifecycle { * Return the SockJsMessageCodec to use. */ public SockJsMessageCodec getMessageCodec() { + Assert.state(this.messageCodec != null, "No SockJsMessageCodec set"); return this.messageCodec; } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsUrlInfo.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsUrlInfo.java index 7d916d4c4c..e01abaabf1 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsUrlInfo.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsUrlInfo.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,6 +19,7 @@ package org.springframework.web.socket.sockjs.client; import java.net.URI; import java.util.UUID; +import org.springframework.lang.Nullable; import org.springframework.util.IdGenerator; import org.springframework.util.JdkIdGenerator; import org.springframework.web.socket.sockjs.transport.TransportType; @@ -39,10 +40,13 @@ public class SockJsUrlInfo { private final URI sockJsUrl; + @Nullable private String serverId; + @Nullable private String sessionId; + @Nullable private UUID uuid; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/WebSocketClientSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/WebSocketClientSockJsSession.java index 2af83497ed..1a4a34b9f3 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/WebSocketClientSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/WebSocketClientSockJsSession.java @@ -39,6 +39,7 @@ import org.springframework.web.socket.adapter.NativeWebSocketSession; */ public class WebSocketClientSockJsSession extends AbstractClientSockJsSession implements NativeWebSocketSession { + @Nullable private WebSocketSession webSocketSession; @@ -51,6 +52,7 @@ public class WebSocketClientSockJsSession extends AbstractClientSockJsSession im @Override public Object getNativeSession() { + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession; } @@ -62,54 +64,50 @@ public class WebSocketClientSockJsSession extends AbstractClientSockJsSession im @Override public InetSocketAddress getLocalAddress() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getLocalAddress(); } @Override public InetSocketAddress getRemoteAddress() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getRemoteAddress(); } @Override public String getAcceptedProtocol() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getAcceptedProtocol(); } @Override public void setTextMessageSizeLimit(int messageSizeLimit) { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); this.webSocketSession.setTextMessageSizeLimit(messageSizeLimit); } @Override public int getTextMessageSizeLimit() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getTextMessageSizeLimit(); } @Override public void setBinaryMessageSizeLimit(int messageSizeLimit) { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); this.webSocketSession.setBinaryMessageSizeLimit(messageSizeLimit); } @Override public int getBinaryMessageSizeLimit() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getBinaryMessageSizeLimit(); } @Override public List getExtensions() { - checkDelegateSessionInitialized(); - return this.webSocketSession.getExtensions(); - } - - private void checkDelegateSessionInitialized() { Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); + return this.webSocketSession.getExtensions(); } public void initializeDelegateSession(WebSocketSession session) { @@ -118,6 +116,7 @@ public class WebSocketClientSockJsSession extends AbstractClientSockJsSession im @Override protected void sendInternal(TextMessage textMessage) throws IOException { + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); this.webSocketSession.sendMessage(textMessage); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/XhrClientSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/XhrClientSockJsSession.java index ad2be98fab..a03944dc19 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/XhrClientSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/XhrClientSockJsSession.java @@ -58,13 +58,11 @@ public class XhrClientSockJsSession extends AbstractClientSockJsSession { XhrTransport transport, SettableListenableFuture connectFuture) { super(request, handler, connectFuture); - Assert.notNull(transport, "'transport' is required"); + Assert.notNull(transport, "XhrTransport is required"); this.transport = transport; this.headers = request.getHttpRequestHeaders(); this.sendHeaders = new HttpHeaders(); - if (this.headers != null) { - this.sendHeaders.putAll(this.headers); - } + this.sendHeaders.putAll(this.headers); this.sendHeaders.setContentType(MediaType.APPLICATION_JSON); this.sendUrl = request.getSockJsUrlInfo().getTransportUrl(TransportType.XHR_SEND); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlingSockJsService.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlingSockJsService.java index 2257ae4ab5..88b3132e7e 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlingSockJsService.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlingSockJsService.java @@ -69,12 +69,14 @@ public class TransportHandlingSockJsService extends AbstractSockJsService implem private final Map handlers = new HashMap<>(); + @Nullable private SockJsMessageCodec messageCodec; private final List interceptors = new ArrayList<>(); private final Map sessions = new ConcurrentHashMap<>(); + @Nullable private ScheduledFuture sessionCleanupTask; private boolean running; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandler.java index d2c191812d..1cea416038 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandler.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.web.socket.sockjs.transport.handler; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -69,7 +70,7 @@ public class SockJsWebSocketHandler extends TextWebSocketHandler implements SubP webSocketHandler = WebSocketHandlerDecorator.unwrap(webSocketHandler); this.subProtocols = ((webSocketHandler instanceof SubProtocolCapable) ? - new ArrayList<>(((SubProtocolCapable) webSocketHandler).getSubProtocols()) : null); + new ArrayList<>(((SubProtocolCapable) webSocketHandler).getSubProtocols()) : Collections.emptyList()); } @Override diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java index 03685f0a6e..a1dc7d0227 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; - import javax.servlet.ServletRequest; import org.springframework.http.HttpHeaders; @@ -33,6 +32,8 @@ import org.springframework.http.server.ServerHttpAsyncRequestControl; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketExtension; @@ -53,22 +54,31 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { private final Queue messageCache; + @Nullable private volatile URI uri; + @Nullable private volatile HttpHeaders handshakeHeaders; + @Nullable private volatile Principal principal; + @Nullable private volatile InetSocketAddress localAddress; + @Nullable private volatile InetSocketAddress remoteAddress; + @Nullable private volatile String acceptedProtocol; + @Nullable private volatile ServerHttpResponse response; + @Nullable private volatile SockJsFrameFormat frameFormat; + @Nullable private volatile ServerHttpAsyncRequestControl asyncRequestControl; private boolean readyToSend; @@ -84,12 +94,16 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { @Override public URI getUri() { - return this.uri; + URI uri = this.uri; + Assert.state(uri != null, "No initial request yet"); + return uri; } @Override public HttpHeaders getHandshakeHeaders() { - return this.handshakeHeaders; + HttpHeaders headers = this.handshakeHeaders; + Assert.state(headers != null, "No initial request yet"); + return headers; } @Override @@ -202,8 +216,9 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { try { this.response = response; this.frameFormat = frameFormat; - this.asyncRequestControl = request.getAsyncRequestControl(response); - this.asyncRequestControl.start(-1); + ServerHttpAsyncRequestControl control = request.getAsyncRequestControl(response); + this.asyncRequestControl = control; + control.start(-1); disableShallowEtagHeaderFilter(request); // Let "our" handler know before sending the open frame to the remote handler delegateConnectionEstablished(); @@ -241,8 +256,9 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { } this.response = response; this.frameFormat = frameFormat; - this.asyncRequestControl = request.getAsyncRequestControl(response); - this.asyncRequestControl.start(-1); + ServerHttpAsyncRequestControl control = request.getAsyncRequestControl(response); + this.asyncRequestControl = control; + control.start(-1); disableShallowEtagHeaderFilter(request); handleRequestInternal(request, response, false); this.readyToSend = isActive(); @@ -329,12 +345,16 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { @Override protected void writeFrameInternal(SockJsFrame frame) throws IOException { if (isActive()) { - String formattedFrame = this.frameFormat.format(frame); - if (logger.isTraceEnabled()) { - logger.trace("Writing to HTTP response: " + formattedFrame); + SockJsFrameFormat frameFormat = this.frameFormat; + ServerHttpResponse response = this.response; + if (frameFormat != null && response != null) { + String formattedFrame = frameFormat.format(frame); + if (logger.isTraceEnabled()) { + logger.trace("Writing to HTTP response: " + formattedFrame); + } + response.getBody().write(formattedFrame.getBytes(SockJsFrame.CHARSET)); + response.flush(); } - this.response.getBody().write(formattedFrame.getBytes(SockJsFrame.CHARSET)); - this.response.flush(); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java index 6d63e91d51..5f6d96944d 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractSockJsSession.java @@ -107,8 +107,10 @@ public abstract class AbstractSockJsSession implements SockJsSession { private volatile long timeLastActive = this.timeCreated; + @Nullable private ScheduledFuture heartbeatFuture; + @Nullable private HeartbeatTask heartbeatTask; private volatile boolean heartbeatDisabled; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/WebSocketServerSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/WebSocketServerSockJsSession.java index c70be2876c..5b5410e97e 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/WebSocketServerSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/WebSocketServerSockJsSession.java @@ -26,6 +26,7 @@ import java.util.Queue; import java.util.concurrent.LinkedBlockingDeque; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.socket.CloseStatus; @@ -47,6 +48,7 @@ import org.springframework.web.socket.sockjs.transport.SockJsServiceConfig; */ public class WebSocketServerSockJsSession extends AbstractSockJsSession implements NativeWebSocketSession { + @Nullable private WebSocketSession webSocketSession; private volatile boolean openFrameSent; @@ -61,7 +63,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession implemen public WebSocketServerSockJsSession(String id, SockJsServiceConfig config, - WebSocketHandler handler, Map attributes) { + WebSocketHandler handler, @Nullable Map attributes) { super(id, config, handler, attributes); } @@ -69,76 +71,73 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession implemen @Override public URI getUri() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getUri(); } @Override public HttpHeaders getHandshakeHeaders() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getHandshakeHeaders(); } @Override public Principal getPrincipal() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getPrincipal(); } @Override public InetSocketAddress getLocalAddress() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getLocalAddress(); } @Override public InetSocketAddress getRemoteAddress() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getRemoteAddress(); } @Override public String getAcceptedProtocol() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getAcceptedProtocol(); } @Override public void setTextMessageSizeLimit(int messageSizeLimit) { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); this.webSocketSession.setTextMessageSizeLimit(messageSizeLimit); } @Override public int getTextMessageSizeLimit() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getTextMessageSizeLimit(); } @Override public void setBinaryMessageSizeLimit(int messageSizeLimit) { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); this.webSocketSession.setBinaryMessageSizeLimit(messageSizeLimit); } @Override public int getBinaryMessageSizeLimit() { - checkDelegateSessionInitialized(); + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return this.webSocketSession.getBinaryMessageSizeLimit(); } @Override public List getExtensions() { - checkDelegateSessionInitialized(); - return this.webSocketSession.getExtensions(); - } - - private void checkDelegateSessionInitialized() { Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); + return this.webSocketSession.getExtensions(); } @Override public Object getNativeSession() { + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); return (this.webSocketSession instanceof NativeWebSocketSession ? ((NativeWebSocketSession) this.webSocketSession).getNativeSession() : this.webSocketSession); } @@ -215,6 +214,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession implemen @Override protected void writeFrameInternal(SockJsFrame frame) throws IOException { + Assert.state(this.webSocketSession != null, "WebSocketSession not yet initialized"); if (logger.isTraceEnabled()) { logger.trace("Writing " + frame); } @@ -228,7 +228,9 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession implemen synchronized (this.disconnectLock) { if (isActive()) { this.disconnected = true; - this.webSocketSession.close(status); + if (this.webSocketSession != null) { + this.webSocketSession.close(status); + } } } } diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/client/XhrTransportTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/client/XhrTransportTests.java index 8fad4a8a7a..d6f6a1435f 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/client/XhrTransportTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/client/XhrTransportTests.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. @@ -75,7 +75,7 @@ public class XhrTransportTests { TestXhrTransport transport = new TestXhrTransport(); transport.sendMessageResponseToReturn = new ResponseEntity<>(HttpStatus.BAD_REQUEST); URI url = new URI("http://example.com"); - transport.executeSendRequest(url, null, new TextMessage("payload")); + transport.executeSendRequest(url, new HttpHeaders(), new TextMessage("payload")); } @Test @@ -86,6 +86,7 @@ public class XhrTransportTests { TransportRequest request = mock(TransportRequest.class); given(request.getSockJsUrlInfo()).willReturn(new SockJsUrlInfo(new URI("http://example.com"))); given(request.getHandshakeHeaders()).willReturn(handshakeHeaders); + given(request.getHttpRequestHeaders()).willReturn(new HttpHeaders()); TestXhrTransport transport = new TestXhrTransport(); WebSocketHandler handler = mock(WebSocketHandler.class); diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandlerTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandlerTests.java index 1d8d0efe8d..fbad787970 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandlerTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/transport/handler/SockJsWebSocketHandlerTests.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. @@ -16,6 +16,8 @@ package org.springframework.web.socket.sockjs.transport.handler; +import java.util.Collections; + import org.junit.Test; import org.springframework.messaging.SubscribableChannel; @@ -59,7 +61,7 @@ public class SockJsWebSocketHandlerTests { WebSocketServerSockJsSession session = new WebSocketServerSockJsSession("1", service, handler, null); SockJsWebSocketHandler sockJsHandler = new SockJsWebSocketHandler(service, handler, session); - assertNull(sockJsHandler.getSubProtocols()); + assertEquals(Collections.emptyList(), sockJsHandler.getSubProtocols()); } }