Polishing

This commit is contained in:
Sam Brannen 2023-10-28 15:05:26 +02:00
parent 1762bf4a60
commit 7f1beb0140
2 changed files with 72 additions and 82 deletions

View File

@ -44,7 +44,6 @@ import org.springframework.util.PatternMatchUtils;
* @author Rob Harrop
* @author Juergen Hoeller
* @author Sam Brannen
* @see #isMatch
* @see NameMatchMethodPointcut
* @see JdkRegexpMethodPointcut
*/
@ -58,7 +57,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
protected final Class<?> clazz;
/**
* An immutable list of method name patterns against which to match.
* An immutable list of distinct method name patterns against which to match.
* @since 6.1
*/
protected final List<String> methodNamePatterns;
@ -184,7 +183,8 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
* Determine if the given method name matches the method name pattern.
* <p>The default implementation checks for direct equality as well as
* {@code xxx*}, {@code *xxx}, {@code *xxx*}, and {@code xxx*yyy} matches.
* <p>Can be overridden in subclasses.
* <p>Can be overridden in subclasses &mdash; for example, to support a
* different style of simple pattern matching.
* @param methodName the method name to check
* @param methodNamePattern the method name pattern
* @return {@code true} if the method name matches the pattern

View File

@ -50,102 +50,35 @@ class ControlFlowPointcutTests {
// Will not be advised: not under MyComponent
assertThat(proxy.getAge()).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(0);
assertThat(cflow.getEvaluations()).isEqualTo(1);
assertThat(nop.getCount()).isEqualTo(0);
// Will be advised due to "getAge" pattern: the proxy is invoked under MyComponent#getAge
assertThat(component.getAge(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(1);
assertThat(cflow.getEvaluations()).isEqualTo(2);
assertThat(nop.getCount()).isEqualTo(1);
// Will not be advised: the proxy is invoked under MyComponent, but there is no match for "nomatch"
assertThat(component.nomatch(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(1);
assertThat(cflow.getEvaluations()).isEqualTo(3);
assertThat(nop.getCount()).isEqualTo(1);
}
@Test
void matchesMethodNamePatterns() {
MyComponent component = new MyComponent();
TestBean target = new TestBean("Jane", 27);
ControlFlowPointcut cflow = pointcut("foo", "get*", "bar", "*se*", "baz");
NopInterceptor nop = new NopInterceptor();
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(new DefaultPointcutAdvisor(cflow, nop));
ITestBean proxy = (ITestBean) pf.getProxy();
ControlFlowPointcut cflow = pointcut("set", "getAge");
assertMatchesSetAndGetAge(cflow);
// Will not be advised: not under MyComponent
assertThat(proxy.getAge()).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(0);
assertThat(cflow.getEvaluations()).isEqualTo(1);
// Will be advised due to "get*" pattern: the proxy is invoked under MyComponent#getAge
assertThat(component.getAge(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(1);
assertThat(cflow.getEvaluations()).isEqualTo(2);
// Will be advised due to "*se*" pattern: the proxy is invoked under MyComponent#set
component.set(proxy);
assertThat(proxy.getAge()).isEqualTo(5);
assertThat(nop.getCount()).isEqualTo(2);
assertThat(cflow.getEvaluations()).isEqualTo(4);
// Will not be advised: the proxy is invoked under MyComponent, but there is no match for "nomatch"
assertThat(component.nomatch(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(2);
assertThat(cflow.getEvaluations()).isEqualTo(5);
cflow = pointcut("foo", "get*", "bar", "*se*", "baz");
assertMatchesSetAndGetAge(cflow);
}
@Test
void controlFlowPointcutIsExtensible() {
@SuppressWarnings("serial")
class CustomControlFlowPointcut extends ControlFlowPointcut {
CustomControlFlowPointcut(Class<?> clazz, String... methodNamePatterns) {
super(clazz, methodNamePatterns);
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
super.incrementEvaluationCount();
return super.matches(method, targetClass, args);
}
Class<?> trackedClass() {
return super.clazz;
}
List<String> trackedMethodNamePatterns() {
return super.methodNamePatterns;
}
}
CustomControlFlowPointcut cflow = new CustomControlFlowPointcut(MyComponent.class, "set*", "getAge", "set*", "set*");
assertMatchesSetAndGetAge(cflow, 2);
assertThat(cflow.trackedClass()).isEqualTo(MyComponent.class);
assertThat(cflow.trackedMethodNamePatterns()).containsExactly("set*", "getAge");
MyComponent component = new MyComponent();
TestBean target = new TestBean("Jane", 27);
NopInterceptor nop = new NopInterceptor();
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(new DefaultPointcutAdvisor(cflow, nop));
ITestBean proxy = (ITestBean) pf.getProxy();
// Will not be advised: the proxy is not invoked under MyComponent#getAge
assertThat(proxy.getAge()).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(0);
assertThat(cflow.getEvaluations()).isEqualTo(2); // intentional double increment
// Will be advised: the proxy is invoked under MyComponent#getAge
assertThat(component.getAge(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(1);
assertThat(cflow.getEvaluations()).isEqualTo(4); // intentional double increment
// Will not be advised: the proxy is invoked under MyComponent, but there is no match for "nomatch"
assertThat(component.nomatch(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(1);
assertThat(cflow.getEvaluations()).isEqualTo(6); // intentional double increment
}
/**
@ -156,25 +89,25 @@ class ControlFlowPointcutTests {
* expensive.
*/
@Test
void selectiveApplication() {
void controlFlowPointcutCanBeCombinedWithStaticPointcut() {
MyComponent component = new MyComponent();
TestBean target = new TestBean("Jane", 27);
ControlFlowPointcut cflow = pointcut();
NopInterceptor nop = new NopInterceptor();
Pointcut settersUnderMyComponent = Pointcuts.intersection(Pointcuts.SETTERS, cflow);
NopInterceptor nop = new NopInterceptor();
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(new DefaultPointcutAdvisor(settersUnderMyComponent, nop));
ITestBean proxy = (ITestBean) pf.getProxy();
// Will not be advised: not under MyComponent
target.setAge(16);
assertThat(nop.getCount()).isEqualTo(0);
assertThat(cflow.getEvaluations()).isEqualTo(0);
assertThat(nop.getCount()).isEqualTo(0);
// Will not be advised: under MyComponent but not a setter
assertThat(component.getAge(proxy)).isEqualTo(16);
assertThat(nop.getCount()).isEqualTo(0);
assertThat(cflow.getEvaluations()).isEqualTo(0);
assertThat(nop.getCount()).isEqualTo(0);
// Will be advised due to Pointcuts.SETTERS: the proxy is invoked under MyComponent#set
component.set(proxy);
@ -246,6 +179,41 @@ class ControlFlowPointcutTests {
return new ControlFlowPointcut(MyComponent.class, methodNamePatterns);
}
private static void assertMatchesSetAndGetAge(ControlFlowPointcut cflow) {
assertMatchesSetAndGetAge(cflow, 1);
}
private static void assertMatchesSetAndGetAge(ControlFlowPointcut cflow, int evaluationFactor) {
MyComponent component = new MyComponent();
TestBean target = new TestBean("Jane", 27);
NopInterceptor nop = new NopInterceptor();
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(new DefaultPointcutAdvisor(cflow, nop));
ITestBean proxy = (ITestBean) pf.getProxy();
// Will not be advised: not under MyComponent
assertThat(proxy.getAge()).isEqualTo(target.getAge());
assertThat(cflow.getEvaluations()).isEqualTo(1 * evaluationFactor);
assertThat(nop.getCount()).isEqualTo(0);
// Will be advised: the proxy is invoked under MyComponent#getAge
assertThat(component.getAge(proxy)).isEqualTo(target.getAge());
assertThat(cflow.getEvaluations()).isEqualTo(2 * evaluationFactor);
assertThat(nop.getCount()).isEqualTo(1);
// Will be advised: the proxy is invoked under MyComponent#set
component.set(proxy);
assertThat(cflow.getEvaluations()).isEqualTo(3 * evaluationFactor);
assertThat(proxy.getAge()).isEqualTo(5);
assertThat(cflow.getEvaluations()).isEqualTo(4 * evaluationFactor);
assertThat(nop.getCount()).isEqualTo(2);
// Will not be advised: the proxy is invoked under MyComponent, but there is no match for "nomatch"
assertThat(component.nomatch(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(2);
assertThat(cflow.getEvaluations()).isEqualTo(5 * evaluationFactor);
}
private static class MyComponent {
int getAge(ITestBean proxy) {
@ -259,4 +227,26 @@ class ControlFlowPointcutTests {
}
}
@SuppressWarnings("serial")
private static class CustomControlFlowPointcut extends ControlFlowPointcut {
CustomControlFlowPointcut(Class<?> clazz, String... methodNamePatterns) {
super(clazz, methodNamePatterns);
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
super.incrementEvaluationCount();
return super.matches(method, targetClass, args);
}
Class<?> trackedClass() {
return super.clazz;
}
List<String> trackedMethodNamePatterns() {
return super.methodNamePatterns;
}
}
}