Skip to content

Commit 92f1f55

Browse files
committed
Refine null-safety in the spring-aop module
Closes gh-34154
1 parent b4a2cdf commit 92f1f55

10 files changed

+23
-17
lines changed

spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -545,14 +545,13 @@ private void configurePointcutParameters(String[] argumentNames, int argumentInd
545545
* @param ex the exception thrown by the method execution (may be null)
546546
* @return the empty array if there are no arguments
547547
*/
548-
@SuppressWarnings("NullAway")
549-
protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
548+
protected @Nullable Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
550549
@Nullable Object returnValue, @Nullable Throwable ex) {
551550

552551
calculateArgumentBindings();
553552

554553
// AMC start
555-
Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
554+
@Nullable Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
556555
int numBound = 0;
557556

558557
if (this.joinPointArgumentIndex != -1) {
@@ -571,19 +570,22 @@ else if (this.joinPointStaticPartArgumentIndex != -1) {
571570
for (PointcutParameter parameter : parameterBindings) {
572571
String name = parameter.getName();
573572
Integer index = this.argumentBindings.get(name);
573+
Assert.notNull(index, "Index must not be null");
574574
adviceInvocationArgs[index] = parameter.getBinding();
575575
numBound++;
576576
}
577577
}
578578
// binding from returning clause
579579
if (this.returningName != null) {
580580
Integer index = this.argumentBindings.get(this.returningName);
581+
Assert.notNull(index, "Index must not be null");
581582
adviceInvocationArgs[index] = returnValue;
582583
numBound++;
583584
}
584585
// binding from thrown exception
585586
if (this.throwingName != null) {
586587
Integer index = this.argumentBindings.get(this.throwingName);
588+
Assert.notNull(index, "Index must not be null");
587589
adviceInvocationArgs[index] = ex;
588590
numBound++;
589591
}

spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, Aspect
8484
* @return the list of {@link org.springframework.aop.Advisor} beans
8585
* @see #isEligibleBean
8686
*/
87-
@SuppressWarnings("NullAway")
8887
public List<Advisor> buildAspectJAdvisors() {
8988
List<String> aspectNames = this.aspectBeanNames;
9089

@@ -158,6 +157,7 @@ public List<Advisor> buildAspectJAdvisors() {
158157
}
159158
else {
160159
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
160+
Assert.notNull(factory, "Factory must not be null");
161161
advisors.addAll(this.advisorFactory.getAdvisors(factory));
162162
}
163163
}

spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,11 @@ final class InstantiationModelAwarePointcutAdvisorImpl
7575

7676
private @Nullable Advice instantiatedAdvice;
7777

78-
private @Nullable Boolean isBeforeAdvice;
78+
@SuppressWarnings("NullAway.Init")
79+
private Boolean isBeforeAdvice;
7980

80-
private @Nullable Boolean isAfterAdvice;
81+
@SuppressWarnings("NullAway.Init")
82+
private Boolean isAfterAdvice;
8183

8284

8385
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
@@ -192,7 +194,6 @@ public int getDeclarationOrder() {
192194
}
193195

194196
@Override
195-
@SuppressWarnings("NullAway")
196197
public boolean isBeforeAdvice() {
197198
if (this.isBeforeAdvice == null) {
198199
determineAdviceType();
@@ -201,7 +202,6 @@ public boolean isBeforeAdvice() {
201202
}
202203

203204
@Override
204-
@SuppressWarnings("NullAway")
205205
public boolean isAfterAdvice() {
206206
if (this.isAfterAdvice == null) {
207207
determineAdviceType();

spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ else if (void.class == returnType || "kotlin.Unit".equals(returnType.getName()))
304304
* @param method the method that was invoked
305305
* @param params the parameters used to invoke the method
306306
*/
307-
protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
307+
protected void handleError(Throwable ex, Method method, @Nullable Object... params) throws Exception {
308308
if (Future.class.isAssignableFrom(method.getReturnType())) {
309309
ReflectionUtils.rethrowException(ex);
310310
}

spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ public AsyncExecutionInterceptor(@Nullable Executor defaultExecutor, AsyncUncaug
9797
* otherwise.
9898
*/
9999
@Override
100-
@SuppressWarnings("NullAway")
101100
public @Nullable Object invoke(final MethodInvocation invocation) throws Throwable {
102101
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
103102
final Method userMethod = BridgeMethodResolver.getMostSpecificMethod(invocation.getMethod(), targetClass);
@@ -116,7 +115,8 @@ public AsyncExecutionInterceptor(@Nullable Executor defaultExecutor, AsyncUncaug
116115
}
117116
}
118117
catch (ExecutionException ex) {
119-
handleError(ex.getCause(), userMethod, invocation.getArguments());
118+
Throwable cause = ex.getCause();
119+
handleError(cause == null ? ex : cause, userMethod, invocation.getArguments());
120120
}
121121
catch (Throwable ex) {
122122
handleError(ex, userMethod, invocation.getArguments());

spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncUncaughtExceptionHandler.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.lang.reflect.Method;
2020

21+
import org.jspecify.annotations.Nullable;
22+
2123
/**
2224
* A strategy for handling uncaught exceptions thrown from asynchronous methods.
2325
*
@@ -38,6 +40,6 @@ public interface AsyncUncaughtExceptionHandler {
3840
* @param method the asynchronous method
3941
* @param params the parameters used to invoke the method
4042
*/
41-
void handleUncaughtException(Throwable ex, Method method, Object... params);
43+
void handleUncaughtException(Throwable ex, Method method, @Nullable Object... params);
4244

4345
}

spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleAsyncUncaughtExceptionHandler.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.apache.commons.logging.Log;
2222
import org.apache.commons.logging.LogFactory;
23+
import org.jspecify.annotations.Nullable;
2324

2425
/**
2526
* A default {@link AsyncUncaughtExceptionHandler} that simply logs the exception.
@@ -34,7 +35,8 @@ public class SimpleAsyncUncaughtExceptionHandler implements AsyncUncaughtExcepti
3435

3536

3637
@Override
37-
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
38+
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1113
39+
public void handleUncaughtException(Throwable ex, Method method, @Nullable Object... params) {
3840
if (logger.isErrorEnabled()) {
3941
logger.error("Unexpected exception occurred invoking async method: " + method, ex);
4042
}

spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessor.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class ScopedProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProc
5353

5454

5555
@Override
56-
@SuppressWarnings("NullAway")
56+
@SuppressWarnings("NullAway") // Lambda
5757
public @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
5858
Class<?> beanClass = registeredBean.getBeanClass();
5959
if (beanClass.equals(ScopedProxyFactoryBean.class)) {

spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public AnnotationMatchingPointcut(@Nullable Class<? extends Annotation> classAnn
8888
* @see AnnotationClassFilter#AnnotationClassFilter(Class, boolean)
8989
* @see AnnotationMethodMatcher#AnnotationMethodMatcher(Class, boolean)
9090
*/
91-
@SuppressWarnings("NullAway")
91+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
9292
public AnnotationMatchingPointcut(@Nullable Class<? extends Annotation> classAnnotationType,
9393
@Nullable Class<? extends Annotation> methodAnnotationType, boolean checkInherited) {
9494

spring-aop/src/main/java/org/springframework/aop/target/dynamic/AbstractRefreshableTargetSource.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public abstract class AbstractRefreshableTargetSource implements TargetSource, R
4242
/** Logger available to subclasses. */
4343
protected final Log logger = LogFactory.getLog(getClass());
4444

45-
protected @Nullable Object targetObject;
45+
@SuppressWarnings("NullAway.Init")
46+
protected Object targetObject;
4647

4748
private long refreshCheckDelay = -1;
4849

@@ -65,7 +66,6 @@ public void setRefreshCheckDelay(long refreshCheckDelay) {
6566

6667

6768
@Override
68-
@SuppressWarnings("NullAway")
6969
public synchronized Class<?> getTargetClass() {
7070
if (this.targetObject == null) {
7171
refresh();

0 commit comments

Comments
 (0)