diff --git a/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java b/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java index e7d89ca7bd6..55cc71ee41b 100644 --- a/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/AfterReturningAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,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(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable; + void afterReturning(@Nullable Object returnValue, Method method, @Nullable Object[] args, @Nullable Object target) throws Throwable; } diff --git a/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java b/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java index 1103590a57a..84963941f6a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/MethodBeforeAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2025 the original author 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,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, @Nullable Object target) throws Throwable; + void before(Method method, @Nullable Object[] args, @Nullable Object target) throws Throwable; } 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 4af259af0d7..26020a327a2 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author 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.aop.support.MethodMatchers; import org.springframework.aop.support.StaticMethodMatcher; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.lang.Contract; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -258,10 +259,11 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence * or in an advice annotation. * @param argumentNames list of argument names */ - public void setArgumentNamesFromStringArray(String... argumentNames) { + public void setArgumentNamesFromStringArray(@Nullable String... argumentNames) { this.argumentNames = new String[argumentNames.length]; for (int i = 0; i < argumentNames.length; i++) { - this.argumentNames[i] = argumentNames[i].strip(); + String argumentName = argumentNames[i]; + this.argumentNames[i] = argumentName != null ? argumentName.strip() : null; if (!isVariableName(this.argumentNames[i])) { throw new IllegalArgumentException( "'argumentNames' property of AbstractAspectJAdvice contains an argument name '" + @@ -274,7 +276,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence if (firstArgType == JoinPoint.class || firstArgType == ProceedingJoinPoint.class || firstArgType == JoinPoint.StaticPart.class) { - String[] oldNames = this.argumentNames; + @Nullable String[] oldNames = this.argumentNames; this.argumentNames = new String[oldNames.length + 1]; this.argumentNames[0] = "THIS_JOIN_POINT"; System.arraycopy(oldNames, 0, this.argumentNames, 1, oldNames.length); @@ -346,7 +348,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence return this.discoveredThrowingType; } - private static boolean isVariableName(String name) { + @Contract("null -> false") + private static boolean isVariableName(@Nullable String name) { return AspectJProxyUtils.isVariableName(name); } @@ -456,6 +459,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence return discoverer; } + @SuppressWarnings("NullAway") // Dataflow analysis limitation private void bindExplicitArguments(int numArgumentsLeftToBind) { Assert.state(this.argumentNames != null, "No argument names available"); this.argumentBindings = new HashMap<>(); @@ -623,8 +627,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t)); } - protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable { - Object[] actualArgs = args; + protected Object invokeAdviceMethodWithGivenArgs(@Nullable Object[] args) throws Throwable { + @Nullable Object[] actualArgs = args; if (this.aspectJAdviceMethod.getParameterCount() == 0) { actualArgs = null; } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java index b0a8a99a54b..bcf9f5a8408 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2025 the original author 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,7 +62,7 @@ public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice } @Override - public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable { + public void afterReturning(@Nullable Object returnValue, Method method, @Nullable Object[] args, @Nullable Object target) throws Throwable { if (shouldInvokeOnReturnValueOf(method, returnValue)) { invokeAdviceMethod(getJoinPointMatch(), returnValue, null); } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java index 561714af575..e8222966d3c 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements @Override - public void before(Method method, Object[] args, @Nullable Object target) throws Throwable { + public void before(Method method, @Nullable Object[] args, @Nullable Object target) throws Throwable { invokeAdviceMethod(getJoinPointMatch(), null, null); } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJProxyUtils.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJProxyUtils.java index 9d287531147..f09ec9d12ed 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJProxyUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJProxyUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author 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.jspecify.annotations.Nullable; import org.springframework.aop.Advisor; import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.interceptor.ExposeInvocationInterceptor; +import org.springframework.lang.Contract; import org.springframework.util.StringUtils; /** @@ -76,6 +77,7 @@ public abstract class AspectJProxyUtils { pointcutAdvisor.getPointcut() instanceof AspectJExpressionPointcut)); } + @Contract("null -> false") static boolean isVariableName(@Nullable String name) { if (!StringUtils.hasLength(name)) { return false; 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 a53d71c84b3..0b2eb35584c 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-2023 the original author or authors. + * Copyright 2002-2025 the original author 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,7 +55,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, private final ProxyMethodInvocation methodInvocation; - private Object @Nullable [] args; + private @Nullable Object @Nullable [] args; /** Lazily initialized signature object. */ private @Nullable Signature signature; @@ -114,7 +114,8 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, } @Override - public Object[] getArgs() { + @SuppressWarnings("NullAway") // Overridden method does not define nullness + public @Nullable Object[] getArgs() { if (this.args == null) { this.args = this.methodInvocation.getArguments().clone(); } @@ -174,7 +175,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, */ private class MethodSignatureImpl implements MethodSignature { - private volatile String @Nullable [] parameterNames; + private volatile @Nullable String @Nullable [] parameterNames; @Override public String getName() { @@ -212,8 +213,9 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, } @Override - public String @Nullable [] getParameterNames() { - String[] parameterNames = this.parameterNames; + @SuppressWarnings("NullAway") // Overridden method does not define nullness + public @Nullable String @Nullable [] getParameterNames() { + @Nullable String[] parameterNames = this.parameterNames; if (parameterNames == null) { parameterNames = parameterNameDiscoverer.getParameterNames(getMethod()); this.parameterNames = parameterNames; 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 1f33f9c8c07..bbe4eea5f0b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -302,7 +302,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto // Now to configure the advice... springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); - String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); + @Nullable String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } 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 bf03bc79b2a..c133292c782 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -704,7 +704,7 @@ class CglibAopProxy implements AopProxy, Serializable { // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. - Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); + @Nullable Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java index ac4c8c0270f..4557f1e315d 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -211,7 +211,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa // We can skip creating a MethodInvocation: just invoke the target directly // Note that the final invoker must be an InvokerInterceptor so we know it does // nothing but a reflective operation on the target, and no hot swapping or fancy proxying. - Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); + @Nullable Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { 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 30110017453..eb07d507843 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -201,7 +201,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea */ @Override public MethodInvocation invocableClone() { - Object[] cloneArguments = this.arguments; + @Nullable Object[] cloneArguments = this.arguments; if (this.arguments.length > 0) { // Build an independent copy of the arguments array. cloneArguments = this.arguments.clone(); 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 ddb1292c48c..26d07c27733 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -116,8 +116,8 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { * applying the corresponding default if a supplier is not resolvable. * @since 5.1 */ - public void configure(@Nullable Supplier defaultExecutor, - @Nullable Supplier exceptionHandler) { + public void configure(@Nullable Supplier defaultExecutor, + @Nullable Supplier exceptionHandler) { this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () -> getDefaultExecutor(this.beanFactory)); this.exceptionHandler = new SingletonSupplier<>(exceptionHandler, SimpleAsyncUncaughtExceptionHandler::new);