Skip to content

Commit

Permalink
Improve ControlFlowPointcut extensibility
Browse files Browse the repository at this point in the history
This commit makes ControlFlowPointcut more open to subclasses by:

1. Making the ControlFlowPointcut#clazz field protected.
2. Making the ControlFlowPointcut#methodName field protected.
3. Introducing a protected incrementEvaluationCount() method.

Closes gh-27187
  • Loading branch information
sbrannen committed Oct 25, 2023
1 parent c0f79ca commit 5c1cdcb
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,18 @@
@SuppressWarnings("serial")
public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {

private final Class<?> clazz;
/**
* The class against which to match.
* <p>Available for use in subclasses since 6.1.
*/
protected final Class<?> clazz;

/**
* The method against which to match, potentially {@code null}.
* <p>Available for use in subclasses since 6.1.
*/
@Nullable
private final String methodName;
protected final String methodName;

private final AtomicInteger evaluationCount = new AtomicInteger();

Expand Down Expand Up @@ -97,7 +105,7 @@ public boolean isRuntime() {

@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
this.evaluationCount.incrementAndGet();
incrementEvaluationCount();

for (StackTraceElement element : new Throwable().getStackTrace()) {
if (element.getClassName().equals(this.clazz.getName()) &&
Expand All @@ -117,6 +125,15 @@ public int getEvaluations() {
return this.evaluationCount.get();
}

/**
* Increment the {@link #getEvaluations() evaluation count}.
* @since 6.1
* @see #matches(Method, Class, Object...)
*/
protected final void incrementEvaluationCount() {
this.evaluationCount.incrementAndGet();
}


@Override
public ClassFilter getClassFilter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.aop.support;

import java.lang.reflect.Method;

import org.junit.jupiter.api.Test;

import org.springframework.aop.Pointcut;
Expand All @@ -31,6 +33,7 @@
*
* @author Rod Johnson
* @author Chris Beams
* @author Sam Brannen
*/
class ControlFlowPointcutTests {

Expand Down Expand Up @@ -60,6 +63,57 @@ void matches() {
assertThat(cflow.getEvaluations()).isEqualTo(3);
}

@Test
void controlFlowPointcutIsExtensible() {
@SuppressWarnings("serial")
class CustomControlFlowPointcut extends ControlFlowPointcut {

CustomControlFlowPointcut(Class<?> clazz, String methodName) {
super(clazz, methodName);
}

@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
super.incrementEvaluationCount();
return super.matches(method, targetClass, args);
}

Class<?> trackedClass() {
return super.clazz;
}

String trackedMethod() {
return super.methodName;
}
}

CustomControlFlowPointcut cflow = new CustomControlFlowPointcut(One.class, "getAge");

assertThat(cflow.trackedClass()).isEqualTo(One.class);
assertThat(cflow.trackedMethod()).isEqualTo("getAge");

TestBean target = new TestBean("Jane", 27);
ProxyFactory pf = new ProxyFactory(target);
NopInterceptor nop = new NopInterceptor();
pf.addAdvisor(new DefaultPointcutAdvisor(cflow, nop));
ITestBean proxy = (ITestBean) pf.getProxy();

// Not advised: the proxy is not invoked under One#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 One#getAge
assertThat(new One().getAge(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(1);
assertThat(cflow.getEvaluations()).isEqualTo(4); // intentional double increment

// Won't be advised: the proxy is not invoked under One#getAge
assertThat(new One().nomatch(proxy)).isEqualTo(target.getAge());
assertThat(nop.getCount()).isEqualTo(1);
assertThat(cflow.getEvaluations()).isEqualTo(6); // intentional double increment
}

/**
* Check that we can use a cflow pointcut only in conjunction with
* a static pointcut: e.g. all setter methods that are invoked under
Expand Down

0 comments on commit 5c1cdcb

Please sign in to comment.