001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.support.annotation; 018 019import java.lang.annotation.Annotation; 020import java.lang.reflect.Method; 021import java.lang.reflect.Proxy; 022 023import org.springframework.aop.support.AopUtils; 024import org.springframework.aop.support.StaticMethodMatcher; 025import org.springframework.core.annotation.AnnotatedElementUtils; 026import org.springframework.lang.Nullable; 027import org.springframework.util.Assert; 028 029/** 030 * Simple MethodMatcher that looks for a specific Java 5 annotation 031 * being present on a method (checking both the method on the invoked 032 * interface, if any, and the corresponding method on the target class). 033 * 034 * @author Juergen Hoeller 035 * @author Sam Brannen 036 * @since 2.0 037 * @see AnnotationMatchingPointcut 038 */ 039public class AnnotationMethodMatcher extends StaticMethodMatcher { 040 041 private final Class<? extends Annotation> annotationType; 042 043 private final boolean checkInherited; 044 045 046 /** 047 * Create a new AnnotationClassFilter for the given annotation type. 048 * @param annotationType the annotation type to look for 049 */ 050 public AnnotationMethodMatcher(Class<? extends Annotation> annotationType) { 051 this(annotationType, false); 052 } 053 054 /** 055 * Create a new AnnotationClassFilter for the given annotation type. 056 * @param annotationType the annotation type to look for 057 * @param checkInherited whether to also check the superclasses and 058 * interfaces as well as meta-annotations for the annotation type 059 * (i.e. whether to use {@link AnnotatedElementUtils#hasAnnotation} 060 * semantics instead of standard Java {@link Method#isAnnotationPresent}) 061 * @since 5.0 062 */ 063 public AnnotationMethodMatcher(Class<? extends Annotation> annotationType, boolean checkInherited) { 064 Assert.notNull(annotationType, "Annotation type must not be null"); 065 this.annotationType = annotationType; 066 this.checkInherited = checkInherited; 067 } 068 069 070 071 @Override 072 public boolean matches(Method method, Class<?> targetClass) { 073 if (matchesMethod(method)) { 074 return true; 075 } 076 // Proxy classes never have annotations on their redeclared methods. 077 if (Proxy.isProxyClass(targetClass)) { 078 return false; 079 } 080 // The method may be on an interface, so let's check on the target class as well. 081 Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); 082 return (specificMethod != method && matchesMethod(specificMethod)); 083 } 084 085 private boolean matchesMethod(Method method) { 086 return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) : 087 method.isAnnotationPresent(this.annotationType)); 088 } 089 090 @Override 091 public boolean equals(@Nullable Object other) { 092 if (this == other) { 093 return true; 094 } 095 if (!(other instanceof AnnotationMethodMatcher)) { 096 return false; 097 } 098 AnnotationMethodMatcher otherMm = (AnnotationMethodMatcher) other; 099 return (this.annotationType.equals(otherMm.annotationType) && this.checkInherited == otherMm.checkInherited); 100 } 101 102 @Override 103 public int hashCode() { 104 return this.annotationType.hashCode(); 105 } 106 107 @Override 108 public String toString() { 109 return getClass().getName() + ": " + this.annotationType; 110 } 111 112}