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; 020 021import org.springframework.aop.ClassFilter; 022import org.springframework.aop.MethodMatcher; 023import org.springframework.aop.Pointcut; 024import org.springframework.util.Assert; 025 026/** 027 * Simple Pointcut that looks for a specific Java 5 annotation 028 * being present on a {@link #forClassAnnotation class} or 029 * {@link #forMethodAnnotation method}. 030 * 031 * @author Juergen Hoeller 032 * @since 2.0 033 * @see AnnotationClassFilter 034 * @see AnnotationMethodMatcher 035 */ 036public class AnnotationMatchingPointcut implements Pointcut { 037 038 private final ClassFilter classFilter; 039 040 private final MethodMatcher methodMatcher; 041 042 043 /** 044 * Create a new AnnotationMatchingPointcut for the given annotation type. 045 * @param classAnnotationType the annotation type to look for at the class level 046 */ 047 public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType) { 048 this(classAnnotationType, false); 049 } 050 051 /** 052 * Create a new AnnotationMatchingPointcut for the given annotation type. 053 * @param classAnnotationType the annotation type to look for at the class level 054 * @param checkInherited whether to also check the superclasses and interfaces 055 * as well as meta-annotations for the annotation type 056 * @see AnnotationClassFilter#AnnotationClassFilter(Class, boolean) 057 */ 058 public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, boolean checkInherited) { 059 this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited); 060 this.methodMatcher = MethodMatcher.TRUE; 061 } 062 063 /** 064 * Create a new AnnotationMatchingPointcut for the given annotation types. 065 * @param classAnnotationType the annotation type to look for at the class level 066 * (can be {@code null}) 067 * @param methodAnnotationType the annotation type to look for at the method level 068 * (can be {@code null}) 069 */ 070 public AnnotationMatchingPointcut( 071 Class<? extends Annotation> classAnnotationType, Class<? extends Annotation> methodAnnotationType) { 072 073 Assert.isTrue((classAnnotationType != null || methodAnnotationType != null), 074 "Either Class annotation type or Method annotation type needs to be specified (or both)"); 075 076 if (classAnnotationType != null) { 077 this.classFilter = new AnnotationClassFilter(classAnnotationType); 078 } 079 else { 080 this.classFilter = ClassFilter.TRUE; 081 } 082 083 if (methodAnnotationType != null) { 084 this.methodMatcher = new AnnotationMethodMatcher(methodAnnotationType); 085 } 086 else { 087 this.methodMatcher = MethodMatcher.TRUE; 088 } 089 } 090 091 092 @Override 093 public ClassFilter getClassFilter() { 094 return this.classFilter; 095 } 096 097 @Override 098 public MethodMatcher getMethodMatcher() { 099 return this.methodMatcher; 100 } 101 102 @Override 103 public boolean equals(Object other) { 104 if (this == other) { 105 return true; 106 } 107 if (!(other instanceof AnnotationMatchingPointcut)) { 108 return false; 109 } 110 AnnotationMatchingPointcut otherPointcut = (AnnotationMatchingPointcut) other; 111 return (this.classFilter.equals(otherPointcut.classFilter) && 112 this.methodMatcher.equals(otherPointcut.methodMatcher)); 113 } 114 115 @Override 116 public int hashCode() { 117 return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode(); 118 } 119 120 @Override 121 public String toString() { 122 return "AnnotationMatchingPointcut: " + this.classFilter + ", " + this.methodMatcher; 123 } 124 125 126 /** 127 * Factory method for an AnnotationMatchingPointcut that matches 128 * for the specified annotation at the class level. 129 * @param annotationType the annotation type to look for at the class level 130 * @return the corresponding AnnotationMatchingPointcut 131 */ 132 public static AnnotationMatchingPointcut forClassAnnotation(Class<? extends Annotation> annotationType) { 133 Assert.notNull(annotationType, "Annotation type must not be null"); 134 return new AnnotationMatchingPointcut(annotationType); 135 } 136 137 /** 138 * Factory method for an AnnotationMatchingPointcut that matches 139 * for the specified annotation at the method level. 140 * @param annotationType the annotation type to look for at the method level 141 * @return the corresponding AnnotationMatchingPointcut 142 */ 143 public static AnnotationMatchingPointcut forMethodAnnotation(Class<? extends Annotation> annotationType) { 144 Assert.notNull(annotationType, "Annotation type must not be null"); 145 return new AnnotationMatchingPointcut(null, annotationType); 146 } 147 148}