Skip to content

Commit 9350091

Browse files
committed
Merge branch '6.0.x'
# Conflicts: # spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java # spring-tx/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionInterceptorTests.java
2 parents 6caef9b + 865fa33 commit 9350091

File tree

43 files changed

+336
-405
lines changed

Some content is hidden

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

43 files changed

+336
-405
lines changed

spring-aop/src/main/java/org/springframework/aop/ClassFilter.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2023 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.
@@ -17,18 +17,23 @@
1717
package org.springframework.aop;
1818

1919
/**
20-
* Filter that restricts matching of a pointcut or introduction to
21-
* a given set of target classes.
20+
* Filter that restricts matching of a pointcut or introduction to a given set
21+
* of target classes.
2222
*
23-
* <p>Can be used as part of a {@link Pointcut} or for the entire
24-
* targeting of an {@link IntroductionAdvisor}.
23+
* <p>Can be used as part of a {@link Pointcut} or for the entire targeting of
24+
* an {@link IntroductionAdvisor}.
2525
*
26-
* <p>Concrete implementations of this interface typically should provide proper
27-
* implementations of {@link Object#equals(Object)} and {@link Object#hashCode()}
28-
* in order to allow the filter to be used in caching scenarios &mdash; for
29-
* example, in proxies generated by CGLIB.
26+
* <p><strong>WARNING</strong>: Concrete implementations of this interface must
27+
* provide proper implementations of {@link Object#equals(Object)},
28+
* {@link Object#hashCode()}, and {@link Object#toString()} in order to allow the
29+
* filter to be used in caching scenarios &mdash; for example, in proxies generated
30+
* by CGLIB. As of Spring Framework 6.0.13, the {@code toString()} implementation
31+
* must generate a unique string representation that aligns with the logic used
32+
* to implement {@code equals()}. See concrete implementations of this interface
33+
* within the framework for examples.
3034
*
3135
* @author Rod Johnson
36+
* @author Sam Brannen
3237
* @see Pointcut
3338
* @see MethodMatcher
3439
*/
@@ -44,7 +49,7 @@ public interface ClassFilter {
4449

4550

4651
/**
47-
* Canonical instance of a ClassFilter that matches all classes.
52+
* Canonical instance of a {@code ClassFilter} that matches all classes.
4853
*/
4954
ClassFilter TRUE = TrueClassFilter.INSTANCE;
5055

spring-aop/src/main/java/org/springframework/aop/MethodMatcher.java

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2023 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,80 +21,84 @@
2121
/**
2222
* Part of a {@link Pointcut}: Checks whether the target method is eligible for advice.
2323
*
24-
* <p>A MethodMatcher may be evaluated <b>statically</b> or at <b>runtime</b> (dynamically).
25-
* Static matching involves method and (possibly) method attributes. Dynamic matching
26-
* also makes arguments for a particular call available, and any effects of running
27-
* previous advice applying to the joinpoint.
24+
* <p>A {@code MethodMatcher} may be evaluated <b>statically</b> or at <b>runtime</b>
25+
* (dynamically). Static matching involves a method and (possibly) method attributes.
26+
* Dynamic matching also makes arguments for a particular call available, and any
27+
* effects of running previous advice applying to the joinpoint.
2828
*
2929
* <p>If an implementation returns {@code false} from its {@link #isRuntime()}
3030
* method, evaluation can be performed statically, and the result will be the same
3131
* for all invocations of this method, whatever their arguments. This means that
3232
* if the {@link #isRuntime()} method returns {@code false}, the 3-arg
33-
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method will never be invoked.
33+
* {@link #matches(Method, Class, Object[])} method will never be invoked.
3434
*
3535
* <p>If an implementation returns {@code true} from its 2-arg
36-
* {@link #matches(java.lang.reflect.Method, Class)} method and its {@link #isRuntime()} method
37-
* returns {@code true}, the 3-arg {@link #matches(java.lang.reflect.Method, Class, Object[])}
38-
* method will be invoked <i>immediately before each potential execution of the related advice</i>,
39-
* to decide whether the advice should run. All previous advice, such as earlier interceptors
40-
* in an interceptor chain, will have run, so any state changes they have produced in
41-
* parameters or ThreadLocal state will be available at the time of evaluation.
36+
* {@link #matches(Method, Class)} method and its {@link #isRuntime()} method
37+
* returns {@code true}, the 3-arg {@link #matches(Method, Class, Object[])}
38+
* method will be invoked <i>immediately before each potential execution of the
39+
* related advice</i> to decide whether the advice should run. All previous advice,
40+
* such as earlier interceptors in an interceptor chain, will have run, so any
41+
* state changes they have produced in parameters or {@code ThreadLocal} state will
42+
* be available at the time of evaluation.
4243
*
43-
* <p>Concrete implementations of this interface typically should provide proper
44-
* implementations of {@link Object#equals(Object)} and {@link Object#hashCode()}
45-
* in order to allow the matcher to be used in caching scenarios &mdash; for
46-
* example, in proxies generated by CGLIB.
44+
* <p><strong>WARNING</strong>: Concrete implementations of this interface must
45+
* provide proper implementations of {@link Object#equals(Object)},
46+
* {@link Object#hashCode()}, and {@link Object#toString()} in order to allow the
47+
* matcher to be used in caching scenarios &mdash; for example, in proxies generated
48+
* by CGLIB. As of Spring Framework 6.0.13, the {@code toString()} implementation
49+
* must generate a unique string representation that aligns with the logic used
50+
* to implement {@code equals()}. See concrete implementations of this interface
51+
* within the framework for examples.
4752
*
4853
* @author Rod Johnson
54+
* @author Sam Brannen
4955
* @since 11.11.2003
5056
* @see Pointcut
5157
* @see ClassFilter
5258
*/
5359
public interface MethodMatcher {
5460

5561
/**
56-
* Perform static checking whether the given method matches.
57-
* <p>If this returns {@code false} or if the {@link #isRuntime()}
58-
* method returns {@code false}, no runtime check (i.e. no
59-
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
60-
* will be made.
62+
* Perform static checking to determine whether the given method matches.
63+
* <p>If this method returns {@code false} or if {@link #isRuntime()}
64+
* returns {@code false}, no runtime check (i.e. no
65+
* {@link #matches(Method, Class, Object[])} call) will be made.
6166
* @param method the candidate method
6267
* @param targetClass the target class
6368
* @return whether this method matches statically
6469
*/
6570
boolean matches(Method method, Class<?> targetClass);
6671

6772
/**
68-
* Is this MethodMatcher dynamic, that is, must a final call be made on the
69-
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
70-
* runtime even if the 2-arg matches method returns {@code true}?
73+
* Is this {@code MethodMatcher} dynamic, that is, must a final check be made
74+
* via the {@link #matches(Method, Class, Object[])} method at runtime even
75+
* if {@link #matches(Method, Class)} returns {@code true}?
7176
* <p>Can be invoked when an AOP proxy is created, and need not be invoked
72-
* again before each method invocation,
73-
* @return whether a runtime match via the 3-arg
74-
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method
77+
* again before each method invocation.
78+
* @return whether a runtime match via {@link #matches(Method, Class, Object[])}
7579
* is required if static matching passed
7680
*/
7781
boolean isRuntime();
7882

7983
/**
80-
* Check whether there a runtime (dynamic) match for this method,
81-
* which must have matched statically.
82-
* <p>This method is invoked only if the 2-arg matches method returns
83-
* {@code true} for the given method and target class, and if the
84-
* {@link #isRuntime()} method returns {@code true}. Invoked
85-
* immediately before potential running of the advice, after any
84+
* Check whether there is a runtime (dynamic) match for this method, which
85+
* must have matched statically.
86+
* <p>This method is invoked only if {@link #matches(Method, Class)} returns
87+
* {@code true} for the given method and target class, and if
88+
* {@link #isRuntime()} returns {@code true}.
89+
* <p>Invoked immediately before potential running of the advice, after any
8690
* advice earlier in the advice chain has run.
8791
* @param method the candidate method
8892
* @param targetClass the target class
8993
* @param args arguments to the method
9094
* @return whether there's a runtime match
91-
* @see MethodMatcher#matches(Method, Class)
95+
* @see #matches(Method, Class)
9296
*/
9397
boolean matches(Method method, Class<?> targetClass, Object... args);
9498

9599

96100
/**
97-
* Canonical instance that matches all methods.
101+
* Canonical instance of a {@code MethodMatcher} that matches all methods.
98102
*/
99103
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
100104

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.aop.support.DynamicMethodMatcherPointcut;
3333
import org.springframework.aop.support.Pointcuts;
3434
import org.springframework.lang.Nullable;
35+
import org.springframework.util.ObjectUtils;
3536

3637
/**
3738
* Internal implementation of AspectJPointcutAdvisor.
@@ -40,6 +41,7 @@
4041
*
4142
* @author Rod Johnson
4243
* @author Juergen Hoeller
44+
* @author Sam Brannen
4345
* @since 2.0
4446
*/
4547
@SuppressWarnings("serial")
@@ -297,6 +299,23 @@ public boolean matches(Method method, Class<?> targetClass, Object... args) {
297299
private boolean isAspectMaterialized() {
298300
return (this.aspectInstanceFactory == null || this.aspectInstanceFactory.isMaterialized());
299301
}
302+
303+
@Override
304+
public boolean equals(@Nullable Object other) {
305+
return (this == other || (other instanceof PerTargetInstantiationModelPointcut that &&
306+
ObjectUtils.nullSafeEquals(this.declaredPointcut.getExpression(), that.declaredPointcut.getExpression())));
307+
}
308+
309+
@Override
310+
public int hashCode() {
311+
return ObjectUtils.nullSafeHashCode(this.declaredPointcut.getExpression());
312+
}
313+
314+
@Override
315+
public String toString() {
316+
return PerTargetInstantiationModelPointcut.class.getName() + ": " + this.declaredPointcut.getExpression();
317+
}
318+
300319
}
301320

302321
}

spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,21 @@
4848

4949
/**
5050
* Base class for AOP proxy configuration managers.
51-
* These are not themselves AOP proxies, but subclasses of this class are
51+
*
52+
* <p>These are not themselves AOP proxies, but subclasses of this class are
5253
* normally factories from which AOP proxy instances are obtained directly.
5354
*
5455
* <p>This class frees subclasses of the housekeeping of Advices
5556
* and Advisors, but doesn't actually implement proxy creation
5657
* methods, which are provided by subclasses.
5758
*
5859
* <p>This class is serializable; subclasses need not be.
59-
* This class is used to hold snapshots of proxies.
60+
*
61+
* <p>This class is used to hold snapshots of proxies.
6062
*
6163
* @author Rod Johnson
6264
* @author Juergen Hoeller
65+
* @author Sam Brannen
6366
* @see org.springframework.aop.framework.AopProxy
6467
*/
6568
public class AdvisedSupport extends ProxyConfig implements Advised {
@@ -111,7 +114,7 @@ public AdvisedSupport() {
111114
}
112115

113116
/**
114-
* Create a AdvisedSupport instance with the given parameters.
117+
* Create an {@code AdvisedSupport} instance with the given parameters.
115118
* @param interfaces the proxied interfaces
116119
*/
117120
public AdvisedSupport(Class<?>... interfaces) {
@@ -131,7 +134,7 @@ private AdvisedSupport(AdvisorChainFactory advisorChainFactory, Map<MethodCacheK
131134

132135
/**
133136
* Set the given object as target.
134-
* Will create a SingletonTargetSource for the object.
137+
* <p>Will create a SingletonTargetSource for the object.
135138
* @see #setTargetSource
136139
* @see org.springframework.aop.target.SingletonTargetSource
137140
*/
@@ -500,9 +503,9 @@ protected void copyConfigurationFrom(AdvisedSupport other) {
500503
}
501504

502505
/**
503-
* Copy the AOP configuration from the given AdvisedSupport object,
504-
* but allow substitution of a fresh TargetSource and a given interceptor chain.
505-
* @param other the AdvisedSupport object to take proxy configuration from
506+
* Copy the AOP configuration from the given {@link AdvisedSupport} object,
507+
* but allow substitution of a fresh {@link TargetSource} and a given interceptor chain.
508+
* @param other the {@code AdvisedSupport} object to take proxy configuration from
506509
* @param targetSource the new TargetSource
507510
* @param advisors the Advisors for the chain
508511
*/
@@ -522,8 +525,8 @@ protected void copyConfigurationFrom(AdvisedSupport other, TargetSource targetSo
522525
}
523526

524527
/**
525-
* Build a configuration-only copy of this AdvisedSupport,
526-
* replacing the TargetSource.
528+
* Build a configuration-only copy of this {@link AdvisedSupport},
529+
* replacing the {@link TargetSource}.
527530
*/
528531
AdvisedSupport getConfigurationOnlyCopy() {
529532
AdvisedSupport copy = new AdvisedSupport(this.advisorChainFactory, this.methodCache);
@@ -598,8 +601,7 @@ public MethodCacheKey(Method method) {
598601

599602
@Override
600603
public boolean equals(@Nullable Object other) {
601-
return (this == other || (other instanceof MethodCacheKey methodCacheKey &&
602-
this.method == methodCacheKey.method));
604+
return (this == other || (other instanceof MethodCacheKey that && this.method == that.method));
603605
}
604606

605607
@Override
@@ -624,7 +626,7 @@ public int compareTo(MethodCacheKey other) {
624626

625627

626628
/**
627-
* Stub for an Advisor instance that is just needed for key purposes,
629+
* Stub for an {@link Advisor} instance that is just needed for key purposes,
628630
* allowing for efficient equals and hashCode comparisons against the
629631
* advice class and the pointcut.
630632
* @since 6.0.10
@@ -636,17 +638,22 @@ private static class AdvisorKeyEntry implements Advisor {
636638
private final Class<?> adviceType;
637639

638640
@Nullable
639-
private String classFilterKey;
641+
private final String classFilterKey;
640642

641643
@Nullable
642-
private String methodMatcherKey;
644+
private final String methodMatcherKey;
645+
643646

644647
public AdvisorKeyEntry(Advisor advisor) {
645648
this.adviceType = advisor.getAdvice().getClass();
646649
if (advisor instanceof PointcutAdvisor pointcutAdvisor) {
647650
Pointcut pointcut = pointcutAdvisor.getPointcut();
648-
this.classFilterKey = ObjectUtils.identityToString(pointcut.getClassFilter());
649-
this.methodMatcherKey = ObjectUtils.identityToString(pointcut.getMethodMatcher());
651+
this.classFilterKey = pointcut.getClassFilter().toString();
652+
this.methodMatcherKey = pointcut.getMethodMatcher().toString();
653+
}
654+
else {
655+
this.classFilterKey = null;
656+
this.methodMatcherKey = null;
650657
}
651658
}
652659

@@ -657,10 +664,10 @@ public Advice getAdvice() {
657664

658665
@Override
659666
public boolean equals(Object other) {
660-
return (this == other || (other instanceof AdvisorKeyEntry otherEntry &&
661-
this.adviceType == otherEntry.adviceType &&
662-
ObjectUtils.nullSafeEquals(this.classFilterKey, otherEntry.classFilterKey) &&
663-
ObjectUtils.nullSafeEquals(this.methodMatcherKey, otherEntry.methodMatcherKey)));
667+
return (this == other || (other instanceof AdvisorKeyEntry that &&
668+
this.adviceType == that.adviceType &&
669+
ObjectUtils.nullSafeEquals(this.classFilterKey, that.classFilterKey) &&
670+
ObjectUtils.nullSafeEquals(this.methodMatcherKey, that.methodMatcherKey)));
664671
}
665672

666673
@Override

spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,17 @@
4040
import org.aspectj.lang.reflect.MethodSignature;
4141
import org.junit.jupiter.api.Disabled;
4242
import org.junit.jupiter.api.Test;
43-
import test.aop.DefaultLockable;
44-
import test.aop.Lockable;
45-
import test.aop.PerTargetAspect;
46-
import test.aop.TwoAdviceAspect;
4743

4844
import org.springframework.aop.Advisor;
4945
import org.springframework.aop.framework.Advised;
5046
import org.springframework.aop.framework.AopConfigException;
5147
import org.springframework.aop.framework.ProxyFactory;
5248
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
5349
import org.springframework.aop.support.AopUtils;
50+
import org.springframework.aop.testfixture.aspectj.PerTargetAspect;
51+
import org.springframework.aop.testfixture.aspectj.TwoAdviceAspect;
52+
import org.springframework.aop.testfixture.mixin.DefaultLockable;
53+
import org.springframework.aop.testfixture.mixin.Lockable;
5454
import org.springframework.beans.testfixture.beans.ITestBean;
5555
import org.springframework.beans.testfixture.beans.TestBean;
5656
import org.springframework.core.OrderComparator;
@@ -459,10 +459,10 @@ void twoAdvicesOnOneAspect() {
459459
assertThat(advisors).as("Two advice methods found").hasSize(2);
460460
ITestBean itb = createProxy(target, ITestBean.class, advisors);
461461
itb.setName("");
462-
assertThat(itb.getAge()).isEqualTo(0);
462+
assertThat(itb.age()).isEqualTo(0);
463463
int newAge = 32;
464464
itb.setAge(newAge);
465-
assertThat(itb.getAge()).isEqualTo(1);
465+
assertThat(itb.age()).isEqualTo(1);
466466
}
467467

468468
@Test

spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2023 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.
@@ -17,13 +17,13 @@
1717
package org.springframework.aop.aspectj.annotation;
1818

1919
import org.junit.jupiter.api.Test;
20-
import test.aop.PerTargetAspect;
2120

2221
import org.springframework.aop.Pointcut;
2322
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
2423
import org.springframework.aop.aspectj.AspectJExpressionPointcutTests;
2524
import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionThrowingAspect;
2625
import org.springframework.aop.framework.AopConfigException;
26+
import org.springframework.aop.testfixture.aspectj.PerTargetAspect;
2727
import org.springframework.beans.testfixture.beans.TestBean;
2828

2929
import static org.assertj.core.api.Assertions.assertThat;

0 commit comments

Comments
 (0)