Introduce null-safety of Spring Framework API

This commit introduces 2 new @Nullable and @NonNullApi
annotations that leverage JSR 305 (dormant but available via
Findbugs jsr305 dependency and already used by libraries
like OkHttp) meta-annotations to specify explicitly
null-safety of Spring Framework parameters and return values.

In order to avoid adding too much annotations, the
default is set at package level with @NonNullApi and
@Nullable annotations are added when needed at parameter or
return value level. These annotations are intended to be used
on Spring Framework itself but also by other Spring projects.

@Nullable annotations have been introduced based on Javadoc
and search of patterns like "return null;". It is expected that
nullability of Spring Framework API will be polished with
complementary commits.

In practice, this will make the whole Spring Framework API
null-safe for Kotlin projects (when KT-10942 will be fixed)
since Kotlin will be able to leverage these annotations to
know if a parameter or a return value is nullable or not. But
this is also useful for Java developers as well since IntelliJ
IDEA, for example, also understands these annotations to
generate warnings when unsafe nullable usages are detected.

Issue: SPR-15540
This commit is contained in:
Sebastien Deleuze
2017-05-27 08:14:59 +02:00
parent 2d37c966b2
commit 87598f48e4
1315 changed files with 4831 additions and 963 deletions

View File

@@ -16,6 +16,8 @@
package org.aopalliance.aop;
import org.springframework.lang.Nullable;
/**
* Superclass for all AOP infrastructure exceptions.
* Unchecked, as such exceptions are fatal and end user
@@ -41,7 +43,7 @@ public class AspectException extends RuntimeException {
* @param message the exception message
* @param cause the root cause, if any
*/
public AspectException(String message, Throwable cause) {
public AspectException(String message, @Nullable Throwable cause) {
super(message, cause);
}

View File

@@ -16,6 +16,8 @@
package org.aopalliance.intercept;
import org.springframework.lang.Nullable;
/**
* Intercepts calls on an interface on its way to the target. These
* are nested "on top" of the target.
@@ -52,6 +54,7 @@ public interface MethodInterceptor extends Interceptor {
* @throws Throwable if the interceptors or the target object
* throws an exception
*/
@Nullable
Object invoke(MethodInvocation invocation) throws Throwable;
}

View File

@@ -18,6 +18,8 @@ package org.springframework.aop;
import java.lang.reflect.Method;
import org.springframework.lang.Nullable;
/**
* After returning advice is invoked only on normal method return, not if an
* exception is thrown. Such advice can see the return value, but cannot change it.
@@ -39,6 +41,6 @@ public interface AfterReturningAdvice extends AfterAdvice {
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}

View File

@@ -18,6 +18,8 @@ package org.springframework.aop;
import java.lang.reflect.Method;
import org.springframework.lang.Nullable;
/**
* A specialized type of {@link MethodMatcher} that takes into account introductions
* when matching methods. If there are no introductions on the target class,
@@ -39,6 +41,6 @@ public interface IntroductionAwareMethodMatcher extends MethodMatcher {
* asking is the subject on one or more introductions; {@code false} otherwise
* @return whether or not this method matches statically
*/
boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions);
}

View File

@@ -18,6 +18,8 @@ package org.springframework.aop;
import java.lang.reflect.Method;
import org.springframework.lang.Nullable;
/**
* Advice invoked before a method is invoked. Such advices cannot
* prevent the method call proceeding, unless they throw a Throwable.
@@ -39,6 +41,6 @@ public interface MethodBeforeAdvice extends BeforeAdvice {
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void before(Method method, Object[] args, Object target) throws Throwable;
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}

View File

@@ -18,6 +18,8 @@ package org.springframework.aop;
import java.lang.reflect.Method;
import org.springframework.lang.Nullable;
/**
* Part of a {@link Pointcut}: Checks whether the target method is eligible for advice.
*
@@ -57,7 +59,7 @@ public interface MethodMatcher {
* the candidate class must be taken to be the method's declaring class)
* @return whether or not this method matches statically
*/
boolean matches(Method method, Class<?> targetClass);
boolean matches(Method method, @Nullable Class<?> targetClass);
/**
* Is this MethodMatcher dynamic, that is, must a final call be made on the
@@ -86,7 +88,7 @@ public interface MethodMatcher {
* @return whether there's a runtime match
* @see MethodMatcher#matches(Method, Class)
*/
boolean matches(Method method, Class<?> targetClass, Object... args);
boolean matches(Method method, @Nullable Class<?> targetClass, Object... args);
/**

View File

@@ -18,6 +18,8 @@ package org.springframework.aop;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.lang.Nullable;
/**
* Extension of the AOP Alliance {@link org.aopalliance.intercept.MethodInvocation}
* interface, allowing access to the proxy that the method invocation was made through.
@@ -73,7 +75,7 @@ public interface ProxyMethodInvocation extends MethodInvocation {
* @param key the name of the attribute
* @param value the value of the attribute, or {@code null} to reset it
*/
void setUserAttribute(String key, Object value);
void setUserAttribute(String key, @Nullable Object value);
/**
* Return the value of the specified user attribute.
@@ -81,6 +83,7 @@ public interface ProxyMethodInvocation extends MethodInvocation {
* @return the value of the attribute, or {@code null} if not set
* @see #setUserAttribute
*/
@Nullable
Object getUserAttribute(String key);
}

View File

@@ -16,6 +16,8 @@
package org.springframework.aop;
import org.springframework.lang.Nullable;
/**
* Minimal interface for exposing the target class behind a proxy.
*
@@ -34,6 +36,7 @@ public interface TargetClassAware {
* (typically a proxy configuration or an actual proxy).
* @return the target Class, or {@code null} if not known
*/
@Nullable
Class<?> getTargetClass();
}

View File

@@ -16,6 +16,8 @@
package org.springframework.aop;
import org.springframework.lang.Nullable;
/**
* A {@code TargetSource} is used to obtain the current "target" of
* an AOP invocation, which will be invoked via reflection if no around
@@ -58,6 +60,7 @@ public interface TargetSource extends TargetClassAware {
* @return the target object, which contains the joinpoint
* @throws Exception if the target object can't be resolved
*/
@Nullable
Object getTarget() throws Exception;
/**

View File

@@ -42,6 +42,7 @@ import org.springframework.aop.support.MethodMatchers;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -548,7 +549,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
* @param ex the exception thrown by the method execution (may be null)
* @return the empty array if there are no arguments
*/
protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex) {
calculateArgumentBindings();
// AMC start
@@ -607,7 +608,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
* @return the invocation result
* @throws Throwable in case of invocation failure
*/
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex) throws Throwable {
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

View File

@@ -30,6 +30,7 @@ import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -473,6 +474,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
/*
* If the token starts meets Java identifier conventions, it's in.
*/
@Nullable
private String maybeExtractVariableName(String candidateToken) {
if (candidateToken == null || candidateToken.equals("")) {
return null;

View File

@@ -22,6 +22,7 @@ import java.lang.reflect.Type;
import org.springframework.aop.AfterAdvice;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.TypeUtils;
@@ -75,7 +76,7 @@ public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
* @param returnValue the return value of the target method
* @return whether to invoke the advice method for the given return value
*/
private boolean shouldInvokeOnReturnValueOf(Method method, Object returnValue) {
private boolean shouldInvokeOnReturnValueOf(Method method, @Nullable Object returnValue) {
Class<?> type = getDiscoveredReturningType();
Type genericType = getDiscoveredReturningGenericType();
// If we aren't dealing with a raw type, check if generic parameters are assignable.
@@ -94,7 +95,7 @@ public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
* @param returnValue the return value of the target method
* @return whether to invoke the advice method for the given return value and type
*/
private boolean matchesReturnValue(Class<?> type, Method method, Object returnValue) {
private boolean matchesReturnValue(Class<?> type, Method method, @Nullable Object returnValue) {
if (returnValue != null) {
return ClassUtils.isAssignableValue(type, returnValue);
}

View File

@@ -21,6 +21,7 @@ import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterAdvice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.lang.Nullable;
/**
* Utility methods for dealing with AspectJ advisors.
@@ -58,6 +59,7 @@ public abstract class AspectJAopUtils {
* If neither the advisor nor the advice have precedence information, this method
* will return {@code null}.
*/
@Nullable
public static AspectJPrecedenceInformation getAspectJPrecedenceInformationFor(Advisor anAdvisor) {
if (anAdvisor instanceof AspectJPrecedenceInformation) {
return (AspectJPrecedenceInformation) anAdvisor;

View File

@@ -56,6 +56,7 @@ import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -382,6 +383,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
/**
* Get a new pointcut expression based on a target class's loader rather than the default.
*/
@Nullable
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
try {
ClassLoader classLoader = targetClass.getClassLoader();

View File

@@ -29,6 +29,7 @@ import org.aspectj.runtime.internal.AroundClosure;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -109,6 +110,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
* Returns the Spring AOP target. May be {@code null} if there is no target.
*/
@Override
@Nullable
public Object getTarget() {
return this.methodInvocation.getThis();
}

View File

@@ -41,6 +41,7 @@ import org.aspectj.lang.reflect.PerClauseKind;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -125,6 +126,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
* (there <i>should</i> only be one anyway...)
*/
@SuppressWarnings("unchecked")
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
Class<?>[] classesToLookFor = new Class<?>[] {
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
@@ -137,6 +139,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
return null;
}
@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {

View File

@@ -24,6 +24,7 @@ import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.lang.Nullable;
/**
* Interface for factories that can create Spring AOP Advisors from classes
@@ -79,6 +80,7 @@ public interface AspectJAdvisorFactory {
* or if it is a pointcut that will be used by other advice but will not
* create a Spring advice in its own right
*/
@Nullable
Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder, String aspectName);
@@ -98,6 +100,7 @@ public interface AspectJAdvisorFactory {
* @see org.springframework.aop.aspectj.AspectJAfterReturningAdvice
* @see org.springframework.aop.aspectj.AspectJAfterThrowingAdvice
*/
@Nullable
Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName);

View File

@@ -17,6 +17,7 @@
package org.springframework.aop.aspectj.annotation;
import org.springframework.aop.aspectj.AspectInstanceFactory;
import org.springframework.lang.Nullable;
/**
* Subinterface of {@link org.springframework.aop.aspectj.AspectInstanceFactory}
@@ -44,6 +45,7 @@ public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactor
* @return the mutex object (may be {@code null} for no mutex to use)
* @since 4.3
*/
@Nullable
Object getAspectCreationMutex();
}

View File

@@ -50,6 +50,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConvertingComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.comparator.InstanceComparator;
@@ -113,7 +114,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
* @see AspectJExpressionPointcut#setBeanFactory
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader()
*/
public ReflectiveAspectJAdvisorFactory(BeanFactory beanFactory) {
public ReflectiveAspectJAdvisorFactory(@Nullable BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@@ -176,6 +177,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
* @param introductionField the field to introspect
* @return {@code null} if not an Advisor
*/
@Nullable
private Advisor getDeclareParentsAdvisor(Field introductionField) {
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
if (declareParents == null) {
@@ -208,6 +210,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);

View File

@@ -3,4 +3,7 @@
*
* <p>Normally to be used through an AspectJAutoProxyCreator rather than directly.
*/
@NonNullApi
package org.springframework.aop.aspectj.annotation;
import org.springframework.lang.NonNullApi;

View File

@@ -2,4 +2,7 @@
* Base classes enabling auto-proxying based on AspectJ.
* Support for AspectJ annotation aspects resides in the "aspectj.annotation" package.
*/
@NonNullApi
package org.springframework.aop.aspectj.autoproxy;
import org.springframework.lang.NonNullApi;

View File

@@ -8,4 +8,7 @@
* or AspectJ load-time weaver. It is intended to enable the use of a valuable subset of AspectJ
* functionality, with consistent semantics, with the proxy-based Spring AOP framework.
*/
@NonNullApi
package org.springframework.aop.aspectj;
import org.springframework.lang.NonNullApi;

View File

@@ -26,6 +26,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -104,7 +105,7 @@ public abstract class AopConfigUtils {
}
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {

View File

@@ -45,6 +45,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -466,6 +467,7 @@ class ConfigBeanDefinitionParser implements BeanDefinitionParser {
* {@link org.springframework.beans.factory.config.BeanDefinition} for the pointcut if necessary
* and returns its bean name, otherwise returns the bean name of the referred pointcut.
*/
@Nullable
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
parserContext.getReaderContext().error(

View File

@@ -2,4 +2,7 @@
* Support package for declarative AOP configuration,
* with XML schema being the primary configuration format.
*/
@NonNullApi
package org.springframework.aop.config;
import org.springframework.lang.NonNullApi;

View File

@@ -19,6 +19,8 @@ package org.springframework.aop.framework;
import java.lang.reflect.Method;
import java.util.List;
import org.springframework.lang.Nullable;
/**
* Factory interface for advisor chains.
*
@@ -36,6 +38,6 @@ public interface AdvisorChainFactory {
* target object, in which case the method's declaring class is the next best option)
* @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
*/
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class<?> targetClass);
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass);
}

View File

@@ -17,6 +17,7 @@
package org.springframework.aop.framework;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.Nullable;
/**
* Class containing static methods used to obtain information about the current AOP invocation.
@@ -74,7 +75,8 @@ public abstract class AopContext {
* @return the old proxy, which may be {@code null} if none was bound
* @see #currentProxy()
*/
static Object setCurrentProxy(Object proxy) {
@Nullable
static Object setCurrentProxy(@Nullable Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);

View File

@@ -16,6 +16,8 @@
package org.springframework.aop.framework;
import org.springframework.lang.Nullable;
/**
* Delegate interface for a configured AOP proxy, allowing for the creation
* of actual proxy objects.
@@ -48,6 +50,6 @@ public interface AopProxy {
* (or {@code null} for the low-level proxy facility's default)
* @return the new proxy object (never {@code null})
*/
Object getProxy(ClassLoader classLoader);
Object getProxy(@Nullable ClassLoader classLoader);
}

View File

@@ -27,6 +27,7 @@ import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.core.DecoratingProxy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -52,6 +53,7 @@ public abstract class AopProxyUtils {
* @see Advised#getTargetSource()
* @see SingletonTargetSource#getTarget()
*/
@Nullable
public static Object getSingletonTarget(Object candidate) {
if (candidate instanceof Advised) {
TargetSource targetSource = ((Advised) candidate).getTargetSource();

View File

@@ -50,6 +50,7 @@ import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
import org.springframework.core.SmartClassLoader;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -372,7 +373,8 @@ class CglibAopProxy implements AopProxy, Serializable {
* Process a return value. Wraps a return of {@code this} if necessary to be the
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
*/
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
@Nullable
private static Object processReturnType(Object proxy, Object target, Method method, @Nullable Object retVal) {
// Massage return value if necessary
if (retVal != null && retVal == target &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {

View File

@@ -19,6 +19,7 @@ package org.springframework.aop.framework;
import org.aopalliance.intercept.Interceptor;
import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@@ -105,7 +106,7 @@ public class ProxyFactory extends ProxyCreatorSupport {
* (or {@code null} for the low-level proxy facility's default)
* @return the proxy object
*/
public Object getProxy(ClassLoader classLoader) {
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

View File

@@ -9,4 +9,7 @@
*
* <p>These adapters do not depend on any other Spring framework classes to allow such usage.
*/
@NonNullApi
package org.springframework.aop.framework.adapter;
import org.springframework.lang.NonNullApi;

View File

@@ -47,6 +47,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -207,6 +208,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
* Return the owning {@link BeanFactory}.
* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.
*/
@Nullable
protected BeanFactory getBeanFactory() {
return this.beanFactory;
}
@@ -400,6 +402,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
* @return a TargetSource for this bean
* @see #setCustomTargetSourceCreators
*/
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
// We can't create fancy target sources for directly registered singletons.
if (this.customTargetSourceCreators != null &&
@@ -578,7 +581,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
* @see #DO_NOT_PROXY
* @see #PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
*/
@Nullable
protected abstract Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;
Class<?> beanClass, String beanName, @Nullable TargetSource customTargetSource) throws BeansException;
}

View File

@@ -19,6 +19,7 @@ package org.springframework.aop.framework.autoproxy;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Conventions;
import org.springframework.lang.Nullable;
/**
* Utilities for auto-proxy aware components.
@@ -79,6 +80,7 @@ public abstract class AutoProxyUtils {
* @since 4.2.3
* @see org.springframework.beans.factory.BeanFactory#getType(String)
*/
@Nullable
public static Class<?> determineTargetClass(ConfigurableListableBeanFactory beanFactory, String beanName) {
if (beanName == null) {
return null;

View File

@@ -17,6 +17,7 @@
package org.springframework.aop.framework.autoproxy;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.Nullable;
/**
* Holder for the current proxy creation context, as exposed by auto-proxy creators
@@ -37,6 +38,7 @@ public class ProxyCreationContext {
* Return the name of the currently proxied bean instance.
* @return the name of the bean, or {@code null} if none available
*/
@Nullable
public static String getCurrentProxiedBeanName() {
return currentProxiedBeanName.get();
}
@@ -45,7 +47,7 @@ public class ProxyCreationContext {
* Set the name of the currently proxied bean instance.
* @param beanName the name of the bean, or {@code null} to reset it
*/
static void setCurrentProxiedBeanName(String beanName) {
static void setCurrentProxiedBeanName(@Nullable String beanName) {
if (beanName != null) {
currentProxiedBeanName.set(beanName);
}

View File

@@ -17,6 +17,7 @@
package org.springframework.aop.framework.autoproxy;
import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;
/**
* Implementations can create special target sources, such as pooling target
@@ -39,6 +40,7 @@ public interface TargetSourceCreator {
* @return a special TargetSource or {@code null} if this TargetSourceCreator isn't
* interested in the particular bean
*/
@Nullable
TargetSource getTargetSource(Class<?> beanClass, String beanName);
}

View File

@@ -9,4 +9,7 @@
* as post-processors beans are only automatically detected in application contexts.
* Post-processors can be explicitly registered on a ConfigurableBeanFactory instead.
*/
@NonNullApi
package org.springframework.aop.framework.autoproxy;
import org.springframework.lang.NonNullApi;

View File

@@ -35,6 +35,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.lang.Nullable;
/**
* Convenient superclass for
@@ -196,6 +197,7 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
* @param beanName the name of the bean
* @return the AbstractPrototypeBasedTargetSource, or {@code null} if we don't match this
*/
@Nullable
protected abstract AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(
Class<?> beanClass, String beanName);

View File

@@ -1,7 +0,0 @@
<html>
<body>
Generic support classes for target source creation.
</body>
</html>

View File

@@ -12,4 +12,7 @@
* or ApplicationContext. However, proxies can be created programmatically using the
* ProxyFactory class.
*/
@NonNullApi
package org.springframework.aop.framework;
import org.springframework.lang.NonNullApi;

View File

@@ -38,6 +38,7 @@ import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.concurrent.ListenableFuture;
@@ -143,6 +144,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* Should preferably return an {@link AsyncListenableTaskExecutor} implementation.
* @return the executor to use (or {@code null}, but just if no default executor is available)
*/
@Nullable
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
AsyncTaskExecutor executor = this.executors.get(method);
if (executor == null) {
@@ -183,6 +185,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @see #determineAsyncExecutor(Method)
* @see #findQualifiedExecutor(BeanFactory, String)
*/
@Nullable
protected abstract String getExecutorQualifier(Method method);
/**
@@ -192,6 +195,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @since 4.2.6
* @see #getExecutorQualifier(Method)
*/
@Nullable
protected Executor findQualifiedExecutor(BeanFactory beanFactory, String qualifier) {
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
@@ -212,6 +216,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @see #findQualifiedExecutor(BeanFactory, String)
* @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME
*/
@Nullable
protected Executor getDefaultExecutor(BeanFactory beanFactory) {
if (beanFactory != null) {
try {
@@ -256,6 +261,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @param returnType the declared return type (potentially a {@link Future} variant)
* @return the execution result (potentially a corresponding {@link Future} handle)
*/
@Nullable
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
if (CompletableFuture.class.isAssignableFrom(returnType)) {
return CompletableFuture.supplyAsync(new Supplier<Object>() {

View File

@@ -24,6 +24,7 @@ import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.springframework.core.Constants;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StopWatch;
@@ -317,7 +318,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
* @return the formatted output to write to the log
*/
protected String replacePlaceholders(String message, MethodInvocation methodInvocation,
Object returnValue, Throwable throwable, long invocationTime) {
@Nullable Object returnValue, @Nullable Throwable throwable, long invocationTime) {
Matcher matcher = PATTERN.matcher(message);
@@ -371,7 +372,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
* @param returnValue the value returned by the method invocation.
*/
private void appendReturnValue(
MethodInvocation methodInvocation, Matcher matcher, StringBuffer output, Object returnValue) {
MethodInvocation methodInvocation, Matcher matcher, StringBuffer output, @Nullable Object returnValue) {
if (methodInvocation.getMethod().getReturnType() == void.class) {
matcher.appendReplacement(output, "void");

View File

@@ -3,4 +3,7 @@
* More specific interceptors can be found in corresponding
* functionality packages, like "transaction" and "orm".
*/
@NonNullApi
package org.springframework.aop.interceptor;
import org.springframework.lang.NonNullApi;

View File

@@ -17,4 +17,7 @@
* <p>Spring AOP can be used programmatically or (preferably)
* integrated with the Spring IoC container.
*/
@NonNullApi
package org.springframework.aop;
import org.springframework.lang.NonNullApi;

View File

@@ -1,4 +1,7 @@
/**
* Support for AOP-based scoping of target objects, with configurable backend.
*/
@NonNullApi
package org.springframework.aop.scope;
import org.springframework.lang.NonNullApi;

View File

@@ -24,6 +24,7 @@ import org.aopalliance.aop.Advice;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -66,6 +67,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
/**
* Return the name of the advice bean that this advisor refers to, if any.
*/
@Nullable
public String getAdviceBeanName() {
return this.adviceBeanName;
}

View File

@@ -18,6 +18,8 @@ package org.springframework.aop.support;
import java.io.Serializable;
import org.springframework.lang.Nullable;
/**
* Abstract superclass for expression pointcuts,
* offering location and expression properties.
@@ -49,6 +51,7 @@ public abstract class AbstractExpressionPointcut implements ExpressionPointcut,
* @return location information as a human-readable String,
* or {@code null} if none is available
*/
@Nullable
public String getLocation() {
return this.location;
}

View File

@@ -36,6 +36,7 @@ import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodIntrospector;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -187,7 +188,7 @@ public abstract class AopUtils {
* {@code targetClass} doesn't implement it or is {@code null}
* @see org.springframework.util.ClassUtils#getMostSpecificMethod
*/
public static Method getMostSpecificMethod(Method method, Class<?> targetClass) {
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// If we are dealing with method with generic parameters, find the original method.
return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
@@ -324,6 +325,7 @@ public abstract class AopUtils {
* @throws Throwable if thrown by the target method
* @throws org.springframework.aop.AopInvocationException in case of a reflection error
*/
@Nullable
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable {

View File

@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
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;
@@ -59,7 +60,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
* @param clazz the clazz
* @param methodName the name of the method (may be {@code null})
*/
public ControlFlowPointcut(Class<?> clazz, String methodName) {
public ControlFlowPointcut(Class<?> clazz, @Nullable String methodName) {
Assert.notNull(clazz, "Class must not be null");
this.clazz = clazz;
this.methodName = methodName;

View File

@@ -27,6 +27,7 @@ import org.springframework.aop.DynamicIntroductionAdvice;
import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.IntroductionInfo;
import org.springframework.core.Ordered;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -64,7 +65,7 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
* @param introductionInfo the IntroductionInfo that describes
* the interface to introduce (may be {@code null})
*/
public DefaultIntroductionAdvisor(Advice advice, IntroductionInfo introductionInfo) {
public DefaultIntroductionAdvisor(Advice advice, @Nullable IntroductionInfo introductionInfo) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
if (introductionInfo != null) {

View File

@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAwareMethodMatcher;
import org.springframework.aop.MethodMatcher;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -87,7 +88,7 @@ public abstract class MethodMatchers {
* asking is the subject on one or more introductions; {@code false} otherwise
* @return whether or not this method matches statically
*/
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
public static boolean matches(MethodMatcher mm, Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(mm, "MethodMatcher must not be null");
return ((mm instanceof IntroductionAwareMethodMatcher &&
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions)) ||

View File

@@ -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;
/**
@@ -132,6 +133,7 @@ public class RegexpMethodPointcutAdvisor extends AbstractGenericPointcutAdvisor
* will be used.
* @return the Pointcut instance (never {@code null})
*/
@Nullable
protected AbstractRegexpMethodPointcut createPointcut() {
return new JdkRegexpMethodPointcut();
}

View File

@@ -21,6 +21,7 @@ import java.lang.annotation.Annotation;
import org.springframework.aop.ClassFilter;
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;
@@ -69,7 +70,7 @@ public class AnnotationMatchingPointcut implements Pointcut {
* (can be {@code null})
*/
public AnnotationMatchingPointcut(
Class<? extends Annotation> classAnnotationType, Class<? extends Annotation> methodAnnotationType) {
@Nullable Class<? extends Annotation> classAnnotationType, @Nullable Class<? extends Annotation> methodAnnotationType) {
this(classAnnotationType, methodAnnotationType, false);
}

View File

@@ -1,4 +1,7 @@
/**
* Annotation support for AOP pointcuts.
*/
@NonNullApi
package org.springframework.aop.support.annotation;
import org.springframework.lang.NonNullApi;

View File

@@ -1,4 +1,7 @@
/**
* Convenience classes for using Spring's AOP API.
*/
@NonNullApi
package org.springframework.aop.support;
import org.springframework.lang.NonNullApi;

View File

@@ -19,6 +19,7 @@ package org.springframework.aop.target;
import java.io.Serializable;
import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -50,7 +51,7 @@ public class EmptyTargetSource implements TargetSource, Serializable {
* @param targetClass the target Class (may be {@code null})
* @see #getTargetClass()
*/
public static EmptyTargetSource forClass(Class<?> targetClass) {
public static EmptyTargetSource forClass(@Nullable Class<?> targetClass) {
return forClass(targetClass, true);
}
@@ -60,7 +61,7 @@ public class EmptyTargetSource implements TargetSource, Serializable {
* @param isStatic whether the TargetSource should be marked as static
* @see #getTargetClass()
*/
public static EmptyTargetSource forClass(Class<?> targetClass, boolean isStatic) {
public static EmptyTargetSource forClass(@Nullable Class<?> targetClass, boolean isStatic) {
return (targetClass == null && isStatic ? INSTANCE : new EmptyTargetSource(targetClass, isStatic));
}
@@ -81,7 +82,7 @@ public class EmptyTargetSource implements TargetSource, Serializable {
* @param targetClass the target class to expose (may be {@code null})
* @param isStatic whether the TargetSource is marked as static
*/
private EmptyTargetSource(Class<?> targetClass, boolean isStatic) {
private EmptyTargetSource(@Nullable Class<?> targetClass, boolean isStatic) {
this.targetClass = targetClass;
this.isStatic = isStatic;
}

View File

@@ -1,7 +0,0 @@
<html>
<body>
Support for AOP-based refreshing of target objects.
</body>
</html>