Skip to content

Commit

Permalink
[WIP] Ensure ClassFilter and MethodMatcher implementations are cacheable
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrannen committed Sep 18, 2019
1 parent b2aad1c commit d826bfc
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -23,6 +23,11 @@
* <p>Can be used as part of a {@link Pointcut} or for the entire
* targeting of an {@link IntroductionAdvisor}.
*
* <p>Concrete implementations of this interface 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 &mdash; for
* example, in proxies generated by CGLIB.
*
* @author Rod Johnson
* @see Pointcut
* @see MethodMatcher
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -22,13 +22,15 @@
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;

/**
* Spring AOP {@link ClassFilter} implementation using AspectJ type matching.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since 2.0
*/
public class TypePatternClassFilter implements ClassFilter {
Expand Down Expand Up @@ -113,4 +115,21 @@ private String replaceBooleanOperators(String pcExpr) {
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;
}

}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
Expand All @@ -28,6 +29,7 @@
* @author Rod Johnson
* @author Rob Harrop
* @author Juergen Hoeller
* @author Sam Brannen
* @since 11.11.2003
* @see MethodMatchers
* @see Pointcuts
Expand Down Expand Up @@ -89,9 +91,9 @@ public static ClassFilter intersection(ClassFilter[] 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;
}

Expand All @@ -115,6 +117,12 @@ public boolean equals(Object other) {
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.filters);
}

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

}


Expand All @@ -124,9 +132,9 @@ public int hashCode() {
@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;
}

Expand All @@ -150,6 +158,12 @@ public boolean equals(Object other) {
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.filters);
}

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

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@
* @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;

Expand Down Expand Up @@ -142,4 +143,9 @@ public int hashCode() {
return code;
}

@Override
public String toString() {
return getClass().getName() + ": class = " + this.clazz.getName() + "; methodName = " + methodName;
}

}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -168,7 +168,7 @@ public int hashCode() {

@Override
public String toString() {
return ClassUtils.getShortName(getClass()) + ": advice [" + this.advice + "]; interfaces " +
return getClass().getName() + ": advice [" + this.advice + "]; interfaces " +
ClassUtils.classNamesToString(this.interfaces);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -19,19 +19,22 @@
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;
}

Expand All @@ -41,4 +44,20 @@ public boolean matches(Class<?> candidate) {
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();
}

}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -62,7 +62,7 @@ public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationTyp
}

/**
* 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
Expand All @@ -75,7 +75,7 @@ public AnnotationMatchingPointcut(@Nullable Class<? extends Annotation> classAnn
}

/**
* 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
Expand Down Expand Up @@ -138,7 +138,7 @@ public int hashCode() {

@Override
public String toString() {
return "AnnotationMatchingPointcut: " + this.classFilter + ", " +this.methodMatcher;
return "AnnotationMatchingPointcut: " + this.classFilter + ", " + this.methodMatcher;
}


Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -31,6 +31,7 @@
* interface, if any, and the corresponding method on the target class).
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 2.0
* @see AnnotationMatchingPointcut
*/
Expand Down Expand Up @@ -94,7 +95,7 @@ public boolean equals(Object other) {
return false;
}
AnnotationMethodMatcher otherMm = (AnnotationMethodMatcher) other;
return this.annotationType.equals(otherMm.annotationType);
return (this.annotationType.equals(otherMm.annotationType) && this.checkInherited == otherMm.checkInherited);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -26,36 +26,42 @@
import static org.junit.Assert.*;

/**
* 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: java.lang.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: java.lang.Exception, .+RootClassFilter: .+NestedRuntimeException\\]$"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ public void testEqualsAndHashCode() throws Exception {
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();
Expand Down
Loading

0 comments on commit d826bfc

Please sign in to comment.