Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce reverse methods in AOP MethodMatchers and ClassFilters #26725

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -85,6 +85,17 @@ public static ClassFilter intersection(ClassFilter[] classFilters) {
return new IntersectionClassFilter(classFilters);
}

/**
* reverse the given ClassFilter match.
* @param cf the ClassFilter
* @return a distinct ClassFilter that not matches classes
* of the given ClassFilter match
*/
public static ClassFilter reversion(ClassFilter cf) {
Assert.notNull(cf, "ClassFilter must not be null");
return new ReversionClassFilter(cf);
}


/**
* ClassFilter implementation for a union of the given ClassFilters.
Expand Down Expand Up @@ -167,4 +178,40 @@ public String toString() {

}


/**
* ClassFilter implementation for an reversion of the given ClassFilter.
*/
@SuppressWarnings("serial")
private static class ReversionClassFilter implements ClassFilter, Serializable {

private final ClassFilter filter;

ReversionClassFilter(ClassFilter filter) {
this.filter = filter;
}

@Override
public boolean matches(Class<?> clazz) {
return !filter.matches(clazz);
}

@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof ReversionClassFilter &&
this.filter.equals(((ReversionClassFilter)other).filter)));
}

@Override
public int hashCode() {
return 37 * this.filter.hashCode();
}

@Override
public String toString() {
return getClass().getName() + ": " + this.filter;
}

}

}
Expand Up @@ -81,6 +81,16 @@ public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2) {
new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2));
}

/**
* reverse the given MethodMatcher match.
* @param mm the MethodMatcher
* @return a distinct MethodMatcher that not matches methods
* of the given MethodMatcher match
*/
public static MethodMatcher reversion(MethodMatcher mm) {
return new ReversionMethodMatcher(mm);
}

/**
* Apply the given MethodMatcher to the given Method, supporting an
* {@link org.springframework.aop.IntroductionAwareMethodMatcher}
Expand Down Expand Up @@ -351,4 +361,57 @@ public boolean matches(Method method, Class<?> targetClass, boolean hasIntroduct
}
}


/**
* MethodMatcher implementation for an reversion of the given MethodMatcher.
*/
@SuppressWarnings("serial")
private static class ReversionMethodMatcher implements MethodMatcher, Serializable {

protected final MethodMatcher mm;

public ReversionMethodMatcher(MethodMatcher mm) {
Assert.notNull(mm, "MethodMatcher must not be null");
this.mm = mm;
}

@Override
public boolean matches(Method method, Class<?> targetClass) {
return !this.mm.matches(method, targetClass);
}

@Override
public boolean isRuntime() {
return this.mm.isRuntime();
}

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

@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ReversionMethodMatcher)) {
return false;
}
ReversionMethodMatcher that = (ReversionMethodMatcher) other;
return this.mm.equals(that.mm);
}

@Override
public int hashCode() {
return 37 * this.mm.hashCode();
}

@Override
public String toString() {
return getClass().getName() + ": " + this.mm;
}

}

}
Expand Up @@ -66,4 +66,13 @@ void intersection() {
.matches("^.+IntersectionClassFilter: \\[.+RootClassFilter: .+Exception, .+RootClassFilter: .+NestedRuntimeException\\]$");
}

@Test
void reversion() {
assertThat(exceptionFilter.matches(RuntimeException.class)).isTrue();
ClassFilter reversion = ClassFilters.reversion(exceptionFilter);
assertThat(reversion.matches(RuntimeException.class)).isFalse();
assertThat(reversion.toString())
.matches("^.+ReversionClassFilter: .+RootClassFilter: .+Exception$");
}

}
Expand Up @@ -111,6 +111,19 @@ public void testUnionEquals() {
assertThat(second.equals(first)).isTrue();
}

@Test
public void testDynamicAndStaticMethodMatcherReversion() throws Exception {
MethodMatcher getterMatcher = new StartsWithMatcher("get");
MethodMatcher reversion = MethodMatchers.reversion(getterMatcher);
assertThat(reversion.isRuntime()).as("Reversion is a static matcher").isFalse();
assertThat(reversion.matches(ITESTBEAN_GETAGE, TestBean.class)).as("Didn't matched getAge method").isFalse();
assertThat(reversion.matches(IOTHER_ABSQUATULATE, TestBean.class)).as("Matched absquatulate method").isTrue();
reversion = MethodMatchers.reversion(new TestDynamicMethodMatcherWhichDoesNotMatch());
assertThat(reversion.isRuntime()).as("Intersection is a dynamic matcher").isTrue();
assertThat(reversion.matches(ITESTBEAN_SETAGE, TestBean.class)).as("Didn't matched setAge method").isFalse();
assertThat(reversion.matches(ITESTBEAN_SETAGE, TestBean.class, 5)).as("Matched setAge method").isTrue();
}


public static class StartsWithMatcher extends StaticMethodMatcher {

Expand Down