diff --git a/spring-aop/src/main/java/org/springframework/aop/ClassFilter.java b/spring-aop/src/main/java/org/springframework/aop/ClassFilter.java index 7409f77d91d..fa8e2066c07 100644 --- a/spring-aop/src/main/java/org/springframework/aop/ClassFilter.java +++ b/spring-aop/src/main/java/org/springframework/aop/ClassFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -23,6 +23,11 @@ package org.springframework.aop; *
Can be used as part of a {@link Pointcut} or for the entire * targeting of an {@link IntroductionAdvisor}. * + *
Concrete implementations of this interface typically should provide proper + * implementations of {@link Object#equals(Object)} and {@link Object#hashCode()} + * in order to allow the filter to be used in caching scenarios — for + * example, in proxies generated by CGLIB. + * * @author Rod Johnson * @see Pointcut * @see MethodMatcher diff --git a/spring-aop/src/main/java/org/springframework/aop/MethodMatcher.java b/spring-aop/src/main/java/org/springframework/aop/MethodMatcher.java index 95999227185..29127c73d42 100644 --- a/spring-aop/src/main/java/org/springframework/aop/MethodMatcher.java +++ b/spring-aop/src/main/java/org/springframework/aop/MethodMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -40,6 +40,11 @@ import java.lang.reflect.Method; * in an interceptor chain, will have run, so any state changes they have produced in * parameters or ThreadLocal state will be available at the time of evaluation. * + *
Concrete implementations of this interface typically should provide proper + * implementations of {@link Object#equals(Object)} and {@link Object#hashCode()} + * in order to allow the matcher to be used in caching scenarios — for + * example, in proxies generated by CGLIB. + * * @author Rod Johnson * @since 11.11.2003 * @see Pointcut diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java index d5997f84c5b..9239583967d 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -735,6 +735,11 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence public int hashCode() { return this.adviceMethod.hashCode(); } + + @Override + public String toString() { + return getClass().getName() + ": " + this.adviceMethod; + } } } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java index e319bec4b81..cf1dcd929b1 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/TypePatternClassFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. @@ -22,6 +22,7 @@ import org.aspectj.weaver.tools.TypePatternMatcher; import org.springframework.aop.ClassFilter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -29,6 +30,7 @@ import org.springframework.util.StringUtils; * * @author Rod Johnson * @author Juergen Hoeller + * @author Sam Brannen * @since 2.0 */ public class TypePatternClassFilter implements ClassFilter { @@ -113,4 +115,21 @@ public class TypePatternClassFilter implements ClassFilter { result = StringUtils.replace(result, " or ", " || "); return StringUtils.replace(result, " not ", " ! "); } + + @Override + public boolean equals(Object other) { + return (this == other || (other instanceof TypePatternClassFilter && + ObjectUtils.nullSafeEquals(this.typePattern, ((TypePatternClassFilter) other).typePattern))); + } + + @Override + public int hashCode() { + return ObjectUtils.nullSafeHashCode(this.typePattern); + } + + @Override + public String toString() { + return getClass().getName() + ": " + this.typePattern; + } + } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ClassFilters.java b/spring-aop/src/main/java/org/springframework/aop/support/ClassFilters.java index 6cca42fbbf7..746ee133ca8 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ClassFilters.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ClassFilters.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2019 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. @@ -17,6 +17,7 @@ package org.springframework.aop.support; import java.io.Serializable; +import java.util.Arrays; import org.springframework.aop.ClassFilter; import org.springframework.util.Assert; @@ -28,6 +29,7 @@ import org.springframework.util.ObjectUtils; * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller + * @author Sam Brannen * @since 11.11.2003 * @see MethodMatchers * @see Pointcuts @@ -89,9 +91,9 @@ public abstract class ClassFilters { @SuppressWarnings("serial") private static class UnionClassFilter implements ClassFilter, Serializable { - private ClassFilter[] filters; + private final ClassFilter[] filters; - public UnionClassFilter(ClassFilter[] filters) { + UnionClassFilter(ClassFilter[] filters) { this.filters = filters; } @@ -115,6 +117,12 @@ public abstract class ClassFilters { public int hashCode() { return ObjectUtils.nullSafeHashCode(this.filters); } + + @Override + public String toString() { + return getClass().getName() + ": " + Arrays.toString(this.filters); + } + } @@ -124,9 +132,9 @@ public abstract class ClassFilters { @SuppressWarnings("serial") private static class IntersectionClassFilter implements ClassFilter, Serializable { - private ClassFilter[] filters; + private final ClassFilter[] filters; - public IntersectionClassFilter(ClassFilter[] filters) { + IntersectionClassFilter(ClassFilter[] filters) { this.filters = filters; } @@ -150,6 +158,12 @@ public abstract class ClassFilters { public int hashCode() { return ObjectUtils.nullSafeHashCode(this.filters); } + + @Override + public String toString() { + return getClass().getName() + ": " + Arrays.toString(this.filters); + } + } } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java index aa9b2d1b4a2..eb3af72b9fa 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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,12 +24,15 @@ import org.springframework.aop.Pointcut; import org.springframework.util.Assert; /** - * Convenient class for building up pointcuts. All methods return - * ComposablePointcut, so we can use a concise idiom like: + * Convenient class for building up pointcuts. * - * {@code - * Pointcut pc = new ComposablePointcut().union(classFilter).intersection(methodMatcher).intersection(pointcut); - * } + *
All methods return {@code ComposablePointcut}, so we can use concise idioms + * like in the following example. + * + *
Pointcut pc = new ComposablePointcut() + * .union(classFilter) + * .intersection(methodMatcher) + * .intersection(pointcut);* * @author Rod Johnson * @author Juergen Hoeller @@ -199,7 +202,7 @@ public class ComposablePointcut implements Pointcut, Serializable { @Override public String toString() { - return "ComposablePointcut: " + this.classFilter + ", " +this.methodMatcher; + return "ComposablePointcut: " + this.classFilter + ", " + this.methodMatcher; } } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java index 89cb2023ca1..5b24edb5bbf 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java @@ -34,14 +34,15 @@ import org.springframework.util.ObjectUtils; * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller + * @author Sam Brannen */ @SuppressWarnings("serial") public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable { - private Class> clazz; + private final Class> clazz; @Nullable - private String methodName; + private final String methodName; private volatile int evaluations; @@ -142,4 +143,9 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher return code; } + @Override + public String toString() { + return getClass().getName() + ": class = " + this.clazz.getName() + "; methodName = " + methodName; + } + } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java index 65da72f8d34..2dab972470e 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -168,7 +168,7 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil @Override public String toString() { - return ClassUtils.getShortName(getClass()) + ": advice [" + this.advice + "]; interfaces " + + return getClass().getName() + ": advice [" + this.advice + "]; interfaces " + ClassUtils.classNamesToString(this.interfaces); } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java b/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java index 99dc8d89a12..7ba5afb2535 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -34,6 +34,7 @@ import org.springframework.util.Assert; * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller + * @author Sam Brannen * @since 11.11.2003 * @see ClassFilters * @see Pointcuts @@ -155,6 +156,11 @@ public abstract class MethodMatchers { public int hashCode() { return 37 * this.mm1.hashCode() + this.mm2.hashCode(); } + + @Override + public String toString() { + return getClass().getName() + ": " + this.mm1 + ", " + this.mm2; + } } @@ -229,6 +235,11 @@ public abstract class MethodMatchers { // Allow for matching with regular UnionMethodMatcher by providing same hash... return super.hashCode(); } + + @Override + public String toString() { + return getClass().getName() + ": " + this.cf1 + ", " + this.mm1 + ", " + this.cf2 + ", " + this.mm2; + } } @@ -311,6 +322,11 @@ public abstract class MethodMatchers { public int hashCode() { return 37 * this.mm1.hashCode() + this.mm2.hashCode(); } + + @Override + public String toString() { + return getClass().getName() + ": " + this.mm1 + ", " + this.mm2; + } } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java index fff0d54ceb7..1509a1eb6ca 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/NameMatchMethodPointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -25,8 +25,8 @@ import java.util.List; import org.springframework.util.PatternMatchUtils; /** - * Pointcut bean for simple method name matches, as alternative to regexp patterns. - * Does not handle overloaded methods: all methods with a given name will be eligible. + * Pointcut bean for simple method name matches, as an alternative to regexp patterns. + *
Does not handle overloaded methods: all methods with a given name will be eligible. * * @author Juergen Hoeller * @author Rod Johnson @@ -108,4 +108,9 @@ public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut impleme return this.mappedNames.hashCode(); } + @Override + public String toString() { + return getClass().getName() + ": " + this.mappedNames; + } + } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/Pointcuts.java b/spring-aop/src/main/java/org/springframework/aop/support/Pointcuts.java index 826594f0302..39c7e8c0ed2 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/Pointcuts.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/Pointcuts.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -26,7 +26,7 @@ import org.springframework.util.Assert; /** * Pointcut constants for matching getters and setters, * and static methods useful for manipulating and evaluating pointcuts. - * These methods are particularly useful for composing pointcuts + *
These methods are particularly useful for composing pointcuts * using the union and intersection methods. * * @author Rod Johnson @@ -106,6 +106,11 @@ public abstract class Pointcuts { private Object readResolve() { return INSTANCE; } + + @Override + public String toString() { + return "Pointcuts.SETTERS"; + } } @@ -126,6 +131,11 @@ public abstract class Pointcuts { private Object readResolve() { return INSTANCE; } + + @Override + public String toString() { + return "Pointcuts.GETTERS"; + } } } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/RootClassFilter.java b/spring-aop/src/main/java/org/springframework/aop/support/RootClassFilter.java index ad559261e50..3809a303797 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/RootClassFilter.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/RootClassFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -19,19 +19,22 @@ package org.springframework.aop.support; import java.io.Serializable; import org.springframework.aop.ClassFilter; +import org.springframework.util.Assert; /** * Simple ClassFilter implementation that passes classes (and optionally subclasses). * * @author Rod Johnson + * @author Sam Brannen */ @SuppressWarnings("serial") public class RootClassFilter implements ClassFilter, Serializable { - private Class> clazz; + private final Class> clazz; public RootClassFilter(Class> clazz) { + Assert.notNull(clazz, "Class must not be null"); this.clazz = clazz; } @@ -41,4 +44,20 @@ public class RootClassFilter implements ClassFilter, Serializable { return this.clazz.isAssignableFrom(candidate); } + @Override + public boolean equals(Object other) { + return (this == other || (other instanceof RootClassFilter && + this.clazz.equals(((RootClassFilter) other).clazz))); + } + + @Override + public int hashCode() { + return this.clazz.hashCode(); + } + + @Override + public String toString() { + return getClass().getName() + ": " + this.clazz.getName(); + } + } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java index 017ad739fb9..b8c7995e129 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. @@ -62,7 +62,7 @@ public class AnnotationMatchingPointcut implements Pointcut { } /** - * Create a new AnnotationMatchingPointcut for the given annotation type. + * Create a new AnnotationMatchingPointcut for the given annotation types. * @param classAnnotationType the annotation type to look for at the class level * (can be {@code null}) * @param methodAnnotationType the annotation type to look for at the method level @@ -75,7 +75,7 @@ public class AnnotationMatchingPointcut implements Pointcut { } /** - * Create a new AnnotationMatchingPointcut for the given annotation type. + * Create a new AnnotationMatchingPointcut for the given annotation types. * @param classAnnotationType the annotation type to look for at the class level * (can be {@code null}) * @param methodAnnotationType the annotation type to look for at the method level @@ -138,7 +138,7 @@ public class AnnotationMatchingPointcut implements Pointcut { @Override public String toString() { - return "AnnotationMatchingPointcut: " + this.classFilter + ", " +this.methodMatcher; + return "AnnotationMatchingPointcut: " + this.classFilter + ", " + this.methodMatcher; } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java index 53b9030276c..549af4c78be 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -31,6 +31,7 @@ import org.springframework.util.Assert; * interface, if any, and the corresponding method on the target class). * * @author Juergen Hoeller + * @author Sam Brannen * @since 2.0 * @see AnnotationMatchingPointcut */ @@ -94,7 +95,7 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher { return false; } AnnotationMethodMatcher otherMm = (AnnotationMethodMatcher) other; - return this.annotationType.equals(otherMm.annotationType); + return (this.annotationType.equals(otherMm.annotationType) && this.checkInherited == otherMm.checkInherited); } @Override diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java index eac280f2ff3..e806d0a1123 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/TypePatternClassFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2019 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. @@ -34,6 +34,7 @@ import static org.junit.Assert.*; * @author Rod Johnson * @author Rick Evans * @author Chris Beams + * @author Sam Brannen */ public class TypePatternClassFilterTests { @@ -88,4 +89,34 @@ public class TypePatternClassFilterTests { new TypePatternClassFilter().matches(String.class); } + @Test + public void testEquals() { + TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter3 = new TypePatternClassFilter("org.springframework.tests.*"); + + assertEquals(filter1, filter2); + assertNotEquals(filter1, filter3); + } + + @Test + public void testHashCode() { + TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter3 = new TypePatternClassFilter("org.springframework.tests.*"); + + assertEquals(filter1.hashCode(), filter2.hashCode()); + assertNotEquals(filter1.hashCode(), filter3.hashCode()); + } + + @Test + public void testToString() { + TypePatternClassFilter filter1 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + TypePatternClassFilter filter2 = new TypePatternClassFilter("org.springframework.tests.sample.beans.*"); + + assertEquals("org.springframework.aop.aspectj.TypePatternClassFilter: org.springframework.tests.sample.beans.*", + filter1.toString()); + assertEquals(filter1.toString(), filter2.toString()); + } + } diff --git a/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java b/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java index 63f42d8984b..d1555021890 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/ClassFiltersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2019 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. @@ -23,39 +23,46 @@ import org.springframework.core.NestedRuntimeException; import org.springframework.tests.sample.beans.ITestBean; import org.springframework.tests.sample.beans.TestBean; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** + * Unit tests for {@link ClassFilters}. + * * @author Rod Johnson * @author Chris Beams + * @author Sam Brannen */ public class ClassFiltersTests { - private ClassFilter exceptionFilter = new RootClassFilter(Exception.class); + private final ClassFilter exceptionFilter = new RootClassFilter(Exception.class); + + private final ClassFilter interfaceFilter = new RootClassFilter(ITestBean.class); - private ClassFilter itbFilter = new RootClassFilter(ITestBean.class); + private final ClassFilter hasRootCauseFilter = new RootClassFilter(NestedRuntimeException.class); - private ClassFilter hasRootCauseFilter = new RootClassFilter(NestedRuntimeException.class); @Test - public void testUnion() { + public void union() { assertTrue(exceptionFilter.matches(RuntimeException.class)); assertFalse(exceptionFilter.matches(TestBean.class)); - assertFalse(itbFilter.matches(Exception.class)); - assertTrue(itbFilter.matches(TestBean.class)); - ClassFilter union = ClassFilters.union(exceptionFilter, itbFilter); + assertFalse(interfaceFilter.matches(Exception.class)); + assertTrue(interfaceFilter.matches(TestBean.class)); + ClassFilter union = ClassFilters.union(exceptionFilter, interfaceFilter); assertTrue(union.matches(RuntimeException.class)); assertTrue(union.matches(TestBean.class)); + assertTrue(union.toString().matches("^.+UnionClassFilter: \\[.+RootClassFilter: .+Exception, .+RootClassFilter: .+TestBean\\]$")); } @Test - public void testIntersection() { + public void intersection() { assertTrue(exceptionFilter.matches(RuntimeException.class)); assertTrue(hasRootCauseFilter.matches(NestedRuntimeException.class)); ClassFilter intersection = ClassFilters.intersection(exceptionFilter, hasRootCauseFilter); assertFalse(intersection.matches(RuntimeException.class)); assertFalse(intersection.matches(TestBean.class)); assertTrue(intersection.matches(NestedRuntimeException.class)); + assertTrue(intersection.toString().matches("^.+IntersectionClassFilter: \\[.+RootClassFilter: .+Exception, .+RootClassFilter: .+NestedRuntimeException\\]$")); } } diff --git a/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java index cf0c9cc299d..77fdd12113f 100644 --- a/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/support/ControlFlowPointcutTests.java @@ -100,6 +100,14 @@ public class ControlFlowPointcutTests { assertFalse(new ControlFlowPointcut(One.class, "getAge").hashCode() == new ControlFlowPointcut(One.class).hashCode()); } + @Test + public void testToString() { + assertEquals(ControlFlowPointcut.class.getName() + ": class = " + One.class.getName() + "; methodName = null", + new ControlFlowPointcut(One.class).toString()); + assertEquals(ControlFlowPointcut.class.getName() + ": class = " + One.class.getName() + "; methodName = getAge", + new ControlFlowPointcut(One.class, "getAge").toString()); + } + public class One { int getAge(ITestBean proxied) { return proxied.getAge(); diff --git a/spring-aop/src/test/java/org/springframework/aop/support/RootClassFilterTests.java b/spring-aop/src/test/java/org/springframework/aop/support/RootClassFilterTests.java new file mode 100644 index 00000000000..b9ccfe81004 --- /dev/null +++ b/spring-aop/src/test/java/org/springframework/aop/support/RootClassFilterTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2019 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support; + +import org.junit.Test; + +import org.springframework.aop.ClassFilter; +import org.springframework.tests.sample.beans.ITestBean; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link RootClassFilter}. + * + * @author Sam Brannen + * @since 5.1.10 + */ +public class RootClassFilterTests { + + private final ClassFilter filter1 = new RootClassFilter(Exception.class); + private final ClassFilter filter2 = new RootClassFilter(Exception.class); + private final ClassFilter filter3 = new RootClassFilter(ITestBean.class); + + @Test + public void matches() { + assertTrue(filter1.matches(Exception.class)); + assertTrue(filter1.matches(RuntimeException.class)); + assertFalse(filter1.matches(Error.class)); + } + + @Test + public void testEquals() { + assertEquals(filter1, filter2); + assertNotEquals(filter1, filter3); + } + + @Test + public void testHashCode() { + assertEquals(filter1.hashCode(), filter2.hashCode()); + assertNotEquals(filter1.hashCode(), filter3.hashCode()); + } + + @Test + public void testToString() { + assertEquals("org.springframework.aop.support.RootClassFilter: java.lang.Exception", filter1.toString()); + assertEquals(filter1.toString(), filter2.toString()); + } + +} diff --git a/spring-aop/src/test/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcutTests.java b/spring-aop/src/test/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcutTests.java new file mode 100644 index 00000000000..97e7ff6ac1c --- /dev/null +++ b/spring-aop/src/test/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcutTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2019 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.support.annotation; + +import org.junit.Test; + +import org.springframework.aop.ClassFilter; +import org.springframework.aop.MethodMatcher; +import org.springframework.aop.Pointcut; +import org.springframework.beans.factory.annotation.Qualifier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link AnnotationMatchingPointcut}. + * + * @author Sam Brannen + * @since 5.1.10 + */ +public class AnnotationMatchingPointcutTests { + + @Test + public void classLevelPointcuts() { + Pointcut pointcut1 = new AnnotationMatchingPointcut(Qualifier.class, true); + Pointcut pointcut2 = new AnnotationMatchingPointcut(Qualifier.class, true); + Pointcut pointcut3 = new AnnotationMatchingPointcut(Qualifier.class); + + assertEquals(AnnotationClassFilter.class, pointcut1.getClassFilter().getClass()); + assertEquals(AnnotationClassFilter.class, pointcut2.getClassFilter().getClass()); + assertEquals(AnnotationClassFilter.class, pointcut3.getClassFilter().getClass()); + assertTrue(pointcut1.getClassFilter().toString().contains(Qualifier.class.getName())); + + assertEquals(MethodMatcher.TRUE, pointcut1.getMethodMatcher()); + assertEquals(MethodMatcher.TRUE, pointcut2.getMethodMatcher()); + assertEquals(MethodMatcher.TRUE, pointcut3.getMethodMatcher()); + + assertEquals(pointcut1, pointcut2); + assertNotEquals(pointcut1, pointcut3); + assertEquals(pointcut1.hashCode(), pointcut2.hashCode()); + // #1 and #3 have equivalent hash codes even though equals() returns false. + assertEquals(pointcut1.hashCode(), pointcut3.hashCode()); + assertEquals(pointcut1.toString(), pointcut2.toString()); + } + + @Test + public void methodLevelPointcuts() { + Pointcut pointcut1 = new AnnotationMatchingPointcut(null, Qualifier.class, true); + Pointcut pointcut2 = new AnnotationMatchingPointcut(null, Qualifier.class, true); + Pointcut pointcut3 = new AnnotationMatchingPointcut(null, Qualifier.class); + + assertEquals(ClassFilter.TRUE, pointcut1.getClassFilter()); + assertEquals(ClassFilter.TRUE, pointcut2.getClassFilter()); + assertEquals(ClassFilter.TRUE, pointcut3.getClassFilter()); + assertEquals("ClassFilter.TRUE", pointcut1.getClassFilter().toString()); + + assertEquals(AnnotationMethodMatcher.class, pointcut1.getMethodMatcher().getClass()); + assertEquals(AnnotationMethodMatcher.class, pointcut2.getMethodMatcher().getClass()); + assertEquals(AnnotationMethodMatcher.class, pointcut3.getMethodMatcher().getClass()); + + assertEquals(pointcut1, pointcut2); + assertNotEquals(pointcut1, pointcut3); + assertEquals(pointcut1.hashCode(), pointcut2.hashCode()); + // #1 and #3 have equivalent hash codes even though equals() returns false. + assertEquals(pointcut1.hashCode(), pointcut3.hashCode()); + assertEquals(pointcut1.toString(), pointcut2.toString()); + } + + @Test + public void classLevelAndMethodLevelPointcuts() { + Pointcut pointcut1 = new AnnotationMatchingPointcut(Qualifier.class, Qualifier.class, true); + Pointcut pointcut2 = new AnnotationMatchingPointcut(Qualifier.class, Qualifier.class, true); + Pointcut pointcut3 = new AnnotationMatchingPointcut(Qualifier.class, Qualifier.class); + + assertEquals(AnnotationClassFilter.class, pointcut1.getClassFilter().getClass()); + assertEquals(AnnotationClassFilter.class, pointcut2.getClassFilter().getClass()); + assertEquals(AnnotationClassFilter.class, pointcut3.getClassFilter().getClass()); + assertTrue(pointcut1.getClassFilter().toString().contains(Qualifier.class.getName())); + + assertEquals(AnnotationMethodMatcher.class, pointcut1.getMethodMatcher().getClass()); + assertEquals(AnnotationMethodMatcher.class, pointcut2.getMethodMatcher().getClass()); + assertEquals(AnnotationMethodMatcher.class, pointcut3.getMethodMatcher().getClass()); + assertTrue(pointcut1.getMethodMatcher().toString().contains(Qualifier.class.getName())); + + assertEquals(pointcut1, pointcut2); + assertNotEquals(pointcut1, pointcut3); + assertEquals(pointcut1.hashCode(), pointcut2.hashCode()); + // #1 and #3 have equivalent hash codes even though equals() returns false. + assertEquals(pointcut1.hashCode(), pointcut3.hashCode()); + assertEquals(pointcut1.toString(), pointcut2.toString()); + } + +}