Browse Source

Merge pull request #26725 from Jinhui-Z

* pr/26725:
  Polish "Introduce reverse on ClassFilter and MethodFilter"
  Introduce reverse on ClassFilter and MethodFilter

Closes gh-26725
pull/31125/head
Stephane Nicoll 2 years ago
parent
commit
2d377155ab
  1. 49
      spring-aop/src/main/java/org/springframework/aop/support/ClassFilters.java
  2. 56
      spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java
  3. 66
      spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java
  4. 64
      spring-aop/src/test/java/org/springframework/aop/support/MethodMatchersTests.java

49
spring-aop/src/main/java/org/springframework/aop/support/ClassFilters.java

@ -18,6 +18,7 @@ package org.springframework.aop.support; @@ -18,6 +18,7 @@ package org.springframework.aop.support;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;
import org.springframework.aop.ClassFilter;
import org.springframework.lang.Nullable;
@ -85,6 +86,18 @@ public abstract class ClassFilters { @@ -85,6 +86,18 @@ public abstract class ClassFilters {
return new IntersectionClassFilter(classFilters);
}
/**
* Return a class filter that represents the logical negation of the specified
* filter instance.
* @param classFilter the {@link ClassFilter} to negate
* @return a filter that represents the logical negation of the specified filter
* @since 6.1
*/
public static ClassFilter negate(ClassFilter classFilter) {
Assert.notNull(classFilter, "ClassFilter must not be null");
return new NegateClassFilter(classFilter);
}
/**
* ClassFilter implementation for a union of the given ClassFilters.
@ -167,4 +180,40 @@ public abstract class ClassFilters { @@ -167,4 +180,40 @@ public abstract class ClassFilters {
}
/**
* ClassFilter implementation for a logical negation of the given ClassFilter.
*/
@SuppressWarnings("serial")
private static class NegateClassFilter implements ClassFilter, Serializable {
private final ClassFilter original;
NegateClassFilter(ClassFilter original) {
this.original = original;
}
@Override
public boolean matches(Class<?> clazz) {
return !this.original.matches(clazz);
}
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof NegateClassFilter that
&& this.original.equals(that.original)));
}
@Override
public int hashCode() {
return Objects.hash(getClass(), this.original);
}
@Override
public String toString() {
return "Negate " + this.original;
}
}
}

56
spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java

@ -18,6 +18,7 @@ package org.springframework.aop.support; @@ -18,6 +18,7 @@ package org.springframework.aop.support;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Objects;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAwareMethodMatcher;
@ -81,6 +82,18 @@ public abstract class MethodMatchers { @@ -81,6 +82,18 @@ public abstract class MethodMatchers {
new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2));
}
/**
* Return a method matcher that represents the logical negation of the specified
* matcher instance.
* @param methodMatcher the {@link MethodMatcher} to negate
* @return a matcher that represents the logical negation of the specified matcher
* @since 6.1
*/
public static MethodMatcher negate(MethodMatcher methodMatcher) {
Assert.notNull(methodMatcher, "MethodMatcher must not be null");
return new NegateMethodMatcher(methodMatcher);
}
/**
* Apply the given MethodMatcher to the given Method, supporting an
* {@link org.springframework.aop.IntroductionAwareMethodMatcher}
@ -338,4 +351,47 @@ public abstract class MethodMatchers { @@ -338,4 +351,47 @@ public abstract class MethodMatchers {
}
}
@SuppressWarnings("serial")
private static class NegateMethodMatcher implements MethodMatcher, Serializable {
private final MethodMatcher original;
NegateMethodMatcher(MethodMatcher original) {
this.original = original;
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
return !this.original.matches(method, targetClass);
}
@Override
public boolean isRuntime() {
return this.original.isRuntime();
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return !this.original.matches(method, targetClass, args);
}
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof NegateMethodMatcher that
&& this.original.equals(that.original)));
}
@Override
public int hashCode() {
return Objects.hash(getClass(), this.original);
}
@Override
public String toString() {
return "Negate " + this.original;
}
}
}

66
spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,6 +24,9 @@ import org.springframework.beans.testfixture.beans.TestBean; @@ -24,6 +24,9 @@ import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.NestedRuntimeException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Unit tests for {@link ClassFilters}.
@ -66,4 +69,65 @@ class ClassFiltersTests { @@ -66,4 +69,65 @@ class ClassFiltersTests {
.matches("^.+IntersectionClassFilter: \\[.+RootClassFilter: .+Exception, .+RootClassFilter: .+NestedRuntimeException\\]$");
}
@Test
void negateClassFilter() {
ClassFilter filter = mock(ClassFilter.class);
given(filter.matches(String.class)).willReturn(true);
ClassFilter negate = ClassFilters.negate(filter);
assertThat(negate.matches(String.class)).isFalse();
verify(filter).matches(String.class);
}
@Test
void negateTrueClassFilter() {
ClassFilter negate = ClassFilters.negate(ClassFilter.TRUE);
assertThat(negate.matches(String.class)).isFalse();
assertThat(negate.matches(Object.class)).isFalse();
assertThat(negate.matches(Integer.class)).isFalse();
}
@Test
void negateTrueClassFilterAppliedTwice() {
ClassFilter negate = ClassFilters.negate(ClassFilters.negate(ClassFilter.TRUE));
assertThat(negate.matches(String.class)).isTrue();
assertThat(negate.matches(Object.class)).isTrue();
assertThat(negate.matches(Integer.class)).isTrue();
}
@Test
void negateIsNotEqualsToOriginalFilter() {
ClassFilter original = ClassFilter.TRUE;
ClassFilter negate = ClassFilters.negate(original);
assertThat(original).isNotEqualTo(negate);
}
@Test
void negateOnSameFilterIsEquals() {
ClassFilter original = ClassFilter.TRUE;
ClassFilter first = ClassFilters.negate(original);
ClassFilter second = ClassFilters.negate(original);
assertThat(first).isEqualTo(second);
}
@Test
void negateHasNotSameHashCodeAsOriginalFilter() {
ClassFilter original = ClassFilter.TRUE;
ClassFilter negate = ClassFilters.negate(original);
assertThat(original).doesNotHaveSameHashCodeAs(negate);
}
@Test
void negateOnSameFilterHasSameHashCode() {
ClassFilter original = ClassFilter.TRUE;
ClassFilter first = ClassFilters.negate(original);
ClassFilter second = ClassFilters.negate(original);
assertThat(first).hasSameHashCodeAs(second);
}
@Test
void toStringIncludesRepresentationOfOriginalFilter() {
ClassFilter original = ClassFilter.TRUE;
assertThat(ClassFilters.negate(original)).hasToString("Negate " + original);
}
}

64
spring-aop/src/test/java/org/springframework/aop/support/MethodMatchersTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import org.springframework.core.testfixture.io.SerializationTestUtils; @@ -28,6 +28,7 @@ import org.springframework.core.testfixture.io.SerializationTestUtils;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* @author Juergen Hoeller
@ -35,6 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -35,6 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class MethodMatchersTests {
private final static Method TEST_METHOD = mock(Method.class);
private final Method EXCEPTION_GETMESSAGE;
private final Method ITESTBEAN_SETAGE;
@ -111,6 +114,65 @@ public class MethodMatchersTests { @@ -111,6 +114,65 @@ public class MethodMatchersTests {
assertThat(second.equals(first)).isTrue();
}
@Test
void negateMethodMatcher() {
MethodMatcher getterMatcher = new StartsWithMatcher("get");
MethodMatcher negate = MethodMatchers.negate(getterMatcher);
assertThat(negate.matches(ITESTBEAN_SETAGE, int.class)).isTrue();
}
@Test
void negateTrueMethodMatcher() {
MethodMatcher negate = MethodMatchers.negate(MethodMatcher.TRUE);
assertThat(negate.matches(TEST_METHOD, String.class)).isFalse();
assertThat(negate.matches(TEST_METHOD, Object.class)).isFalse();
assertThat(negate.matches(TEST_METHOD, Integer.class)).isFalse();
}
@Test
void negateTrueMethodMatcherAppliedTwice() {
MethodMatcher negate = MethodMatchers.negate(MethodMatchers.negate(MethodMatcher.TRUE));
assertThat(negate.matches(TEST_METHOD, String.class)).isTrue();
assertThat(negate.matches(TEST_METHOD, Object.class)).isTrue();
assertThat(negate.matches(TEST_METHOD, Integer.class)).isTrue();
}
@Test
void negateIsNotEqualsToOriginalMatcher() {
MethodMatcher original = MethodMatcher.TRUE;
MethodMatcher negate = MethodMatchers.negate(original);
assertThat(original).isNotEqualTo(negate);
}
@Test
void negateOnSameMatcherIsEquals() {
MethodMatcher original = MethodMatcher.TRUE;
MethodMatcher first = MethodMatchers.negate(original);
MethodMatcher second = MethodMatchers.negate(original);
assertThat(first).isEqualTo(second);
}
@Test
void negateHasNotSameHashCodeAsOriginalMatcher() {
MethodMatcher original = MethodMatcher.TRUE;
MethodMatcher negate = MethodMatchers.negate(original);
assertThat(original).doesNotHaveSameHashCodeAs(negate);
}
@Test
void negateOnSameMatcherHasSameHashCode() {
MethodMatcher original = MethodMatcher.TRUE;
MethodMatcher first = MethodMatchers.negate(original);
MethodMatcher second = MethodMatchers.negate(original);
assertThat(first).hasSameHashCodeAs(second);
}
@Test
void toStringIncludesRepresentationOfOriginalMatcher() {
MethodMatcher original = MethodMatcher.TRUE;
assertThat(MethodMatchers.negate(original)).hasToString("Negate " + original);
}
public static class StartsWithMatcher extends StaticMethodMatcher {

Loading…
Cancel
Save