Skip to content

Commit cc74a28

Browse files
committed
@nullable all the way: null-safety at field level
This commits extends nullability declarations to the field level, formalizing the interaction between methods and their underlying fields and therefore avoiding any nullability mismatch. Issue: SPR-15720
1 parent c4694c3 commit cc74a28

File tree

936 files changed

+6071
-2787
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

936 files changed

+6071
-2787
lines changed

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ public static JoinPoint currentJoinPoint() {
104104
private final AspectInstanceFactory aspectInstanceFactory;
105105

106106
/**
107-
* The name of the aspect (ref bean) in which this advice was defined (used
108-
* when determining advice precedence so that we can determine
107+
* The name of the aspect (ref bean) in which this advice was defined
108+
* (used when determining advice precedence so that we can determine
109109
* whether two pieces of advice come from the same aspect).
110110
*/
111-
private String aspectName;
111+
private String aspectName = "";
112112

113113
/**
114114
* The order of declaration of this advice within the aspect.
@@ -119,13 +119,16 @@ public static JoinPoint currentJoinPoint() {
119119
* This will be non-null if the creator of this advice object knows the argument names
120120
* and sets them explicitly
121121
*/
122-
private String[] argumentNames = null;
122+
@Nullable
123+
private String[] argumentNames;
123124

124125
/** Non-null if after throwing advice binds the thrown value */
125-
private String throwingName = null;
126+
@Nullable
127+
private String throwingName;
126128

127129
/** Non-null if after returning advice binds the return value */
128-
private String returningName = null;
130+
@Nullable
131+
private String returningName;
129132

130133
private Class<?> discoveredReturningType = Object.class;
131134

@@ -143,10 +146,12 @@ public static JoinPoint currentJoinPoint() {
143146
*/
144147
private int joinPointStaticPartArgumentIndex = -1;
145148

149+
@Nullable
146150
private Map<String, Integer> argumentBindings;
147151

148152
private boolean argumentsIntrospected = false;
149153

154+
@Nullable
150155
private Type discoveredReturningGenericType;
151156
// Note: Unlike return type, no such generic information is needed for the throwing type,
152157
// since Java doesn't allow exception types to be parameterized.
@@ -464,6 +469,7 @@ protected ParameterNameDiscoverer createParameterNameDiscoverer() {
464469
}
465470

466471
private void bindExplicitArguments(int numArgumentsLeftToBind) {
472+
Assert.state(this.argumentNames != null, "No argument names available");
467473
this.argumentBindings = new HashMap<>();
468474

469475
int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount();
@@ -504,36 +510,36 @@ private void bindExplicitArguments(int numArgumentsLeftToBind) {
504510
}
505511

506512
// configure the pointcut expression accordingly.
507-
configurePointcutParameters(argumentIndexOffset);
513+
configurePointcutParameters(this.argumentNames, argumentIndexOffset);
508514
}
509515

510516
/**
511517
* All parameters from argumentIndexOffset onwards are candidates for
512518
* pointcut parameters - but returning and throwing vars are handled differently
513519
* and must be removed from the list if present.
514520
*/
515-
private void configurePointcutParameters(int argumentIndexOffset) {
521+
private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) {
516522
int numParametersToRemove = argumentIndexOffset;
517523
if (this.returningName != null) {
518524
numParametersToRemove++;
519525
}
520526
if (this.throwingName != null) {
521527
numParametersToRemove++;
522528
}
523-
String[] pointcutParameterNames = new String[this.argumentNames.length - numParametersToRemove];
529+
String[] pointcutParameterNames = new String[argumentNames.length - numParametersToRemove];
524530
Class<?>[] pointcutParameterTypes = new Class<?>[pointcutParameterNames.length];
525531
Class<?>[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();
526532

527533
int index = 0;
528-
for (int i = 0; i < this.argumentNames.length; i++) {
534+
for (int i = 0; i < argumentNames.length; i++) {
529535
if (i < argumentIndexOffset) {
530536
continue;
531537
}
532-
if (this.argumentNames[i].equals(this.returningName) ||
533-
this.argumentNames[i].equals(this.throwingName)) {
538+
if (argumentNames[i].equals(this.returningName) ||
539+
argumentNames[i].equals(this.throwingName)) {
534540
continue;
535541
}
536-
pointcutParameterNames[index] = this.argumentNames[i];
542+
pointcutParameterNames[index] = argumentNames[i];
537543
pointcutParameterTypes[index] = methodParameterTypes[i];
538544
index++;
539545
}

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

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
* returning {@code null} in the case that the parameter names cannot be discovered.
115115
*
116116
* @author Adrian Colyer
117+
* @author Juergen Hoeller
117118
* @since 2.0
118119
*/
119120
public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscoverer {
@@ -155,26 +156,23 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
155156
}
156157

157158

159+
/** The pointcut expression associated with the advice, as a simple String */
160+
@Nullable
161+
private String pointcutExpression;
162+
158163
private boolean raiseExceptions;
159164

160-
/**
161-
* If the advice is afterReturning, and binds the return value, this is the parameter name used.
162-
*/
165+
/** If the advice is afterReturning, and binds the return value, this is the parameter name used */
166+
@Nullable
163167
private String returningName;
164168

165-
/**
166-
* If the advice is afterThrowing, and binds the thrown value, this is the parameter name used.
167-
*/
169+
/** If the advice is afterThrowing, and binds the thrown value, this is the parameter name used */
170+
@Nullable
168171
private String throwingName;
169172

170-
/**
171-
* The pointcut expression associated with the advice, as a simple String.
172-
*/
173-
private String pointcutExpression;
174-
175-
private Class<?>[] argumentTypes;
173+
private Class<?>[] argumentTypes = new Class<?>[0];
176174

177-
private String[] parameterNameBindings;
175+
private String[] parameterNameBindings = new String[0];
178176

179177
private int numberOfRemainingUnboundArguments;
180178

@@ -202,7 +200,7 @@ public void setRaiseExceptions(boolean raiseExceptions) {
202200
* returning variable name must be specified.
203201
* @param returningName the name of the returning variable
204202
*/
205-
public void setReturningName(String returningName) {
203+
public void setReturningName(@Nullable String returningName) {
206204
this.returningName = returningName;
207205
}
208206

@@ -211,7 +209,7 @@ public void setReturningName(String returningName) {
211209
* throwing variable name must be specified.
212210
* @param throwingName the name of the throwing variable
213211
*/
214-
public void setThrowingName(String throwingName) {
212+
public void setThrowingName(@Nullable String throwingName) {
215213
this.throwingName = throwingName;
216214
}
217215

@@ -781,6 +779,7 @@ private static class PointcutBody {
781779

782780
private int numTokensConsumed;
783781

782+
@Nullable
784783
private String text;
785784

786785
public PointcutBody(int tokens, @Nullable String text) {

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

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,20 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
102102

103103
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
104104

105+
@Nullable
105106
private Class<?> pointcutDeclarationScope;
106107

107108
private String[] pointcutParameterNames = new String[0];
108109

109110
private Class<?>[] pointcutParameterTypes = new Class<?>[0];
110111

112+
@Nullable
111113
private BeanFactory beanFactory;
112114

115+
@Nullable
113116
private transient ClassLoader pointcutClassLoader;
114117

118+
@Nullable
115119
private transient PointcutExpression pointcutExpression;
116120

117121
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<>(32);
@@ -169,13 +173,13 @@ public void setBeanFactory(BeanFactory beanFactory) {
169173

170174
@Override
171175
public ClassFilter getClassFilter() {
172-
checkReadyToMatch();
176+
obtainPointcutExpression();
173177
return this;
174178
}
175179

176180
@Override
177181
public MethodMatcher getMethodMatcher() {
178-
checkReadyToMatch();
182+
obtainPointcutExpression();
179183
return this;
180184
}
181185

@@ -184,14 +188,15 @@ public MethodMatcher getMethodMatcher() {
184188
* Check whether this pointcut is ready to match,
185189
* lazily building the underlying AspectJ pointcut expression.
186190
*/
187-
private void checkReadyToMatch() {
191+
private PointcutExpression obtainPointcutExpression() {
188192
if (getExpression() == null) {
189193
throw new IllegalStateException("Must set property 'expression' before attempting to match");
190194
}
191195
if (this.pointcutExpression == null) {
192196
this.pointcutClassLoader = determinePointcutClassLoader();
193197
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
194198
}
199+
return this.pointcutExpression;
195200
}
196201

197202
/**
@@ -258,16 +263,15 @@ private String replaceBooleanOperators(String pcExpr) {
258263
* Return the underlying AspectJ pointcut expression.
259264
*/
260265
public PointcutExpression getPointcutExpression() {
261-
checkReadyToMatch();
262-
return this.pointcutExpression;
266+
return obtainPointcutExpression();
263267
}
264268

265269
@Override
266270
public boolean matches(Class<?> targetClass) {
267-
checkReadyToMatch();
271+
PointcutExpression pointcutExpression = obtainPointcutExpression();
268272
try {
269273
try {
270-
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
274+
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
271275
}
272276
catch (ReflectionWorldException ex) {
273277
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
@@ -286,7 +290,7 @@ public boolean matches(Class<?> targetClass) {
286290

287291
@Override
288292
public boolean matches(Method method, @Nullable Class<?> targetClass, boolean beanHasIntroductions) {
289-
checkReadyToMatch();
293+
obtainPointcutExpression();
290294
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
291295
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
292296

@@ -321,13 +325,12 @@ public boolean matches(Method method, @Nullable Class<?> targetClass) {
321325

322326
@Override
323327
public boolean isRuntime() {
324-
checkReadyToMatch();
325-
return this.pointcutExpression.mayNeedDynamicTest();
328+
return obtainPointcutExpression().mayNeedDynamicTest();
326329
}
327330

328331
@Override
329332
public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
330-
checkReadyToMatch();
333+
obtainPointcutExpression();
331334
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
332335
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
333336

@@ -436,7 +439,7 @@ private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
436439
if (shadowMatch == null) {
437440
try {
438441
try {
439-
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
442+
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
440443
}
441444
catch (ReflectionWorldException ex) {
442445
// Failed to introspect target method, probably because it has been loaded
@@ -454,7 +457,7 @@ private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
454457
if (shadowMatch == null && targetMethod != originalMethod) {
455458
methodToMatch = originalMethod;
456459
try {
457-
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
460+
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
458461
}
459462
catch (ReflectionWorldException ex3) {
460463
// Could neither introspect the target class nor the proxy class ->
@@ -519,18 +522,16 @@ public int hashCode() {
519522
public String toString() {
520523
StringBuilder sb = new StringBuilder();
521524
sb.append("AspectJExpressionPointcut: ");
522-
if (this.pointcutParameterNames != null && this.pointcutParameterTypes != null) {
523-
sb.append("(");
524-
for (int i = 0; i < this.pointcutParameterTypes.length; i++) {
525-
sb.append(this.pointcutParameterTypes[i].getName());
526-
sb.append(" ");
527-
sb.append(this.pointcutParameterNames[i]);
528-
if ((i+1) < this.pointcutParameterTypes.length) {
529-
sb.append(", ");
530-
}
525+
sb.append("(");
526+
for (int i = 0; i < this.pointcutParameterTypes.length; i++) {
527+
sb.append(this.pointcutParameterTypes[i].getName());
528+
sb.append(" ");
529+
sb.append(this.pointcutParameterNames[i]);
530+
if ((i+1) < this.pointcutParameterTypes.length) {
531+
sb.append(", ");
531532
}
532-
sb.append(")");
533533
}
534+
sb.append(")");
534535
sb.append(" ");
535536
if (getExpression() != null) {
536537
sb.append(getExpression());

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import org.springframework.aop.Pointcut;
2222
import org.springframework.aop.PointcutAdvisor;
2323
import org.springframework.core.Ordered;
24+
import org.springframework.lang.Nullable;
2425
import org.springframework.util.Assert;
2526
import org.springframework.util.ObjectUtils;
2627

@@ -38,6 +39,7 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
3839

3940
private final Pointcut pointcut;
4041

42+
@Nullable
4143
private Integer order;
4244

4345

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,12 +57,15 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
5757

5858
private final ProxyMethodInvocation methodInvocation;
5959

60+
@Nullable
6061
private Object[] defensiveCopyOfArgs;
6162

6263
/** Lazily initialized signature object */
64+
@Nullable
6365
private Signature signature;
6466

6567
/** Lazily initialized source location object */
68+
@Nullable
6669
private SourceLocation sourceLocation;
6770

6871

@@ -178,6 +181,7 @@ public String toString() {
178181
*/
179182
private class MethodSignatureImpl implements MethodSignature {
180183

184+
@Nullable
181185
private volatile String[] parameterNames;
182186

183187
@Override
@@ -216,6 +220,7 @@ public Class<?>[] getParameterTypes() {
216220
}
217221

218222
@Override
223+
@Nullable
219224
public String[] getParameterNames() {
220225
if (this.parameterNames == null) {
221226
this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,6 +37,7 @@
3737
import org.aspectj.weaver.reflect.ShadowMatchImpl;
3838
import org.aspectj.weaver.tools.ShadowMatch;
3939

40+
import org.springframework.lang.Nullable;
4041
import org.springframework.util.ClassUtils;
4142
import org.springframework.util.ReflectionUtils;
4243

@@ -78,6 +79,7 @@ class RuntimeTestWalker {
7879
}
7980

8081

82+
@Nullable
8183
private final Test runtimeTest;
8284

8385

0 commit comments

Comments
 (0)