/*
 * 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 java.io.Serializable;
import java.lang.reflect.Method;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAwareMethodMatcher;
import org.springframework.aop.MethodMatcher;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

Static utility methods for composing MethodMatchers.

A MethodMatcher may be evaluated statically (based on method and target class) or need further evaluation dynamically (based on arguments at the time of method invocation).

Author:Rod Johnson, Rob Harrop, Juergen Hoeller, Sam Brannen
See Also:
Since:11.11.2003
/** * Static utility methods for composing {@link MethodMatcher MethodMatchers}. * * <p>A MethodMatcher may be evaluated statically (based on method and target * class) or need further evaluation dynamically (based on arguments at the * time of method invocation). * * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller * @author Sam Brannen * @since 11.11.2003 * @see ClassFilters * @see Pointcuts */
public abstract class MethodMatchers {
Match all methods that either (or both) of the given MethodMatchers matches.
Params:
  • mm1 – the first MethodMatcher
  • mm2 – the second MethodMatcher
Returns:a distinct MethodMatcher that matches all methods that either of the given MethodMatchers matches
/** * Match all methods that <i>either</i> (or both) of the given MethodMatchers matches. * @param mm1 the first MethodMatcher * @param mm2 the second MethodMatcher * @return a distinct MethodMatcher that matches all methods that either * of the given MethodMatchers matches */
public static MethodMatcher union(MethodMatcher mm1, MethodMatcher mm2) { return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ? new UnionIntroductionAwareMethodMatcher(mm1, mm2) : new UnionMethodMatcher(mm1, mm2)); }
Match all methods that either (or both) of the given MethodMatchers matches.
Params:
  • mm1 – the first MethodMatcher
  • cf1 – the corresponding ClassFilter for the first MethodMatcher
  • mm2 – the second MethodMatcher
  • cf2 – the corresponding ClassFilter for the second MethodMatcher
Returns:a distinct MethodMatcher that matches all methods that either of the given MethodMatchers matches
/** * Match all methods that <i>either</i> (or both) of the given MethodMatchers matches. * @param mm1 the first MethodMatcher * @param cf1 the corresponding ClassFilter for the first MethodMatcher * @param mm2 the second MethodMatcher * @param cf2 the corresponding ClassFilter for the second MethodMatcher * @return a distinct MethodMatcher that matches all methods that either * of the given MethodMatchers matches */
static MethodMatcher union(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) { return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ? new ClassFilterAwareUnionIntroductionAwareMethodMatcher(mm1, cf1, mm2, cf2) : new ClassFilterAwareUnionMethodMatcher(mm1, cf1, mm2, cf2)); }
Match all methods that both of the given MethodMatchers match.
Params:
  • mm1 – the first MethodMatcher
  • mm2 – the second MethodMatcher
Returns:a distinct MethodMatcher that matches all methods that both of the given MethodMatchers match
/** * Match all methods that <i>both</i> of the given MethodMatchers match. * @param mm1 the first MethodMatcher * @param mm2 the second MethodMatcher * @return a distinct MethodMatcher that matches all methods that both * of the given MethodMatchers match */
public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2) { return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ? new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2)); }
Apply the given MethodMatcher to the given Method, supporting an IntroductionAwareMethodMatcher (if applicable).
Params:
  • mm – the MethodMatcher to apply (may be an IntroductionAwareMethodMatcher)
  • method – the candidate method
  • targetClass – the target class
  • hasIntroductions – true if the object on whose behalf we are asking is the subject on one or more introductions; false otherwise
Returns:whether or not this method matches statically
/** * Apply the given MethodMatcher to the given Method, supporting an * {@link org.springframework.aop.IntroductionAwareMethodMatcher} * (if applicable). * @param mm the MethodMatcher to apply (may be an IntroductionAwareMethodMatcher) * @param method the candidate method * @param targetClass the target class * @param hasIntroductions {@code true} if the object on whose behalf we are * asking is the subject on one or more introductions; {@code false} otherwise * @return whether or not this method matches statically */
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(mm, "MethodMatcher must not be null"); return (mm instanceof IntroductionAwareMethodMatcher ? ((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) : mm.matches(method, targetClass)); }
MethodMatcher implementation for a union of two given MethodMatchers.
/** * MethodMatcher implementation for a union of two given MethodMatchers. */
@SuppressWarnings("serial") private static class UnionMethodMatcher implements MethodMatcher, Serializable { protected final MethodMatcher mm1; protected final MethodMatcher mm2; public UnionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) { Assert.notNull(mm1, "First MethodMatcher must not be null"); Assert.notNull(mm2, "Second MethodMatcher must not be null"); this.mm1 = mm1; this.mm2 = mm2; } @Override public boolean matches(Method method, Class<?> targetClass) { return (matchesClass1(targetClass) && this.mm1.matches(method, targetClass)) || (matchesClass2(targetClass) && this.mm2.matches(method, targetClass)); } protected boolean matchesClass1(Class<?> targetClass) { return true; } protected boolean matchesClass2(Class<?> targetClass) { return true; } @Override public boolean isRuntime() { return this.mm1.isRuntime() || this.mm2.isRuntime(); } @Override public boolean matches(Method method, Class<?> targetClass, Object... args) { return this.mm1.matches(method, targetClass, args) || this.mm2.matches(method, targetClass, args); } @Override public boolean equals(@Nullable Object other) { if (this == other) { return true; } if (!(other instanceof UnionMethodMatcher)) { return false; } UnionMethodMatcher that = (UnionMethodMatcher) other; return (this.mm1.equals(that.mm1) && this.mm2.equals(that.mm2)); } @Override public int hashCode() { return 37 * this.mm1.hashCode() + this.mm2.hashCode(); } @Override public String toString() { return getClass().getName() + ": " + this.mm1 + ", " + this.mm2; } }
MethodMatcher implementation for a union of two given MethodMatchers of which at least one is an IntroductionAwareMethodMatcher.
Since:5.1
/** * MethodMatcher implementation for a union of two given MethodMatchers * of which at least one is an IntroductionAwareMethodMatcher. * @since 5.1 */
@SuppressWarnings("serial") private static class UnionIntroductionAwareMethodMatcher extends UnionMethodMatcher implements IntroductionAwareMethodMatcher { public UnionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) { super(mm1, mm2); } @Override public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) { return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) || (matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions)); } }
MethodMatcher implementation for a union of two given MethodMatchers, supporting an associated ClassFilter per MethodMatcher.
/** * MethodMatcher implementation for a union of two given MethodMatchers, * supporting an associated ClassFilter per MethodMatcher. */
@SuppressWarnings("serial") private static class ClassFilterAwareUnionMethodMatcher extends UnionMethodMatcher { private final ClassFilter cf1; private final ClassFilter cf2; public ClassFilterAwareUnionMethodMatcher(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) { super(mm1, mm2); this.cf1 = cf1; this.cf2 = cf2; } @Override protected boolean matchesClass1(Class<?> targetClass) { return this.cf1.matches(targetClass); } @Override protected boolean matchesClass2(Class<?> targetClass) { return this.cf2.matches(targetClass); } @Override public boolean equals(@Nullable Object other) { if (this == other) { return true; } if (!super.equals(other)) { return false; } ClassFilter otherCf1 = ClassFilter.TRUE; ClassFilter otherCf2 = ClassFilter.TRUE; if (other instanceof ClassFilterAwareUnionMethodMatcher) { ClassFilterAwareUnionMethodMatcher cfa = (ClassFilterAwareUnionMethodMatcher) other; otherCf1 = cfa.cf1; otherCf2 = cfa.cf2; } return (this.cf1.equals(otherCf1) && this.cf2.equals(otherCf2)); } @Override public int hashCode() { // 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; } }
MethodMatcher implementation for a union of two given MethodMatchers of which at least one is an IntroductionAwareMethodMatcher, supporting an associated ClassFilter per MethodMatcher.
Since:5.1
/** * MethodMatcher implementation for a union of two given MethodMatchers * of which at least one is an IntroductionAwareMethodMatcher, * supporting an associated ClassFilter per MethodMatcher. * @since 5.1 */
@SuppressWarnings("serial") private static class ClassFilterAwareUnionIntroductionAwareMethodMatcher extends ClassFilterAwareUnionMethodMatcher implements IntroductionAwareMethodMatcher { public ClassFilterAwareUnionIntroductionAwareMethodMatcher( MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) { super(mm1, cf1, mm2, cf2); } @Override public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) { return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) || (matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions)); } }
MethodMatcher implementation for an intersection of two given MethodMatchers.
/** * MethodMatcher implementation for an intersection of two given MethodMatchers. */
@SuppressWarnings("serial") private static class IntersectionMethodMatcher implements MethodMatcher, Serializable { protected final MethodMatcher mm1; protected final MethodMatcher mm2; public IntersectionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) { Assert.notNull(mm1, "First MethodMatcher must not be null"); Assert.notNull(mm2, "Second MethodMatcher must not be null"); this.mm1 = mm1; this.mm2 = mm2; } @Override public boolean matches(Method method, Class<?> targetClass) { return (this.mm1.matches(method, targetClass) && this.mm2.matches(method, targetClass)); } @Override public boolean isRuntime() { return (this.mm1.isRuntime() || this.mm2.isRuntime()); } @Override public boolean matches(Method method, Class<?> targetClass, Object... args) { // Because a dynamic intersection may be composed of a static and dynamic part, // we must avoid calling the 3-arg matches method on a dynamic matcher, as // it will probably be an unsupported operation. boolean aMatches = (this.mm1.isRuntime() ? this.mm1.matches(method, targetClass, args) : this.mm1.matches(method, targetClass)); boolean bMatches = (this.mm2.isRuntime() ? this.mm2.matches(method, targetClass, args) : this.mm2.matches(method, targetClass)); return aMatches && bMatches; } @Override public boolean equals(@Nullable Object other) { if (this == other) { return true; } if (!(other instanceof IntersectionMethodMatcher)) { return false; } IntersectionMethodMatcher that = (IntersectionMethodMatcher) other; return (this.mm1.equals(that.mm1) && this.mm2.equals(that.mm2)); } @Override public int hashCode() { return 37 * this.mm1.hashCode() + this.mm2.hashCode(); } @Override public String toString() { return getClass().getName() + ": " + this.mm1 + ", " + this.mm2; } }
MethodMatcher implementation for an intersection of two given MethodMatchers of which at least one is an IntroductionAwareMethodMatcher.
Since:5.1
/** * MethodMatcher implementation for an intersection of two given MethodMatchers * of which at least one is an IntroductionAwareMethodMatcher. * @since 5.1 */
@SuppressWarnings("serial") private static class IntersectionIntroductionAwareMethodMatcher extends IntersectionMethodMatcher implements IntroductionAwareMethodMatcher { public IntersectionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) { super(mm1, mm2); } @Override public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) { return (MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions)); } } }