Specify generic type nullness in spring-aop

See gh-34140
This commit is contained in:
Sébastien Deleuze 2025-01-13 20:50:30 +01:00
parent c0039fb624
commit f52f83349c
12 changed files with 41 additions and 33 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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();

View File

@ -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<Executor> defaultExecutor,
@Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
public void configure(@Nullable Supplier<? extends @Nullable Executor> defaultExecutor,
@Nullable Supplier<? extends @Nullable AsyncUncaughtExceptionHandler> exceptionHandler) {
this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () -> getDefaultExecutor(this.beanFactory));
this.exceptionHandler = new SingletonSupplier<>(exceptionHandler, SimpleAsyncUncaughtExceptionHandler::new);