package org.googlecode.perftrace.aopmatcher.support.annotation; import java.lang.annotation.Annotation; import org.googlecode.perftrace.aopmatcher.ClassFilter; /** * Simple ClassFilter that looks for a specific Java 5 annotation * being present on a class. */ public class AnnotationClassFilter implements ClassFilter { private final Class<? extends Annotation> annotationType; private final boolean checkInherited; /** * Create a new AnnotationClassFilter for the given annotation type. * @param annotationType the annotation type to look for */ public AnnotationClassFilter(Class<? extends Annotation> annotationType) { this(annotationType, false); } /** * Create a new AnnotationClassFilter for the given annotation type. * @param annotationType the annotation type to look for * @param checkInherited whether to explicitly check the superclasses and * interfaces for the annotation type as well (even if the annotation type * is not marked as inherited itself) */ public AnnotationClassFilter(Class<? extends Annotation> annotationType, boolean checkInherited) { //Assert.notNull(annotationType, "Annotation type must not be null"); this.annotationType = annotationType; this.checkInherited = checkInherited; } public boolean matches(Class clazz) { return (this.checkInherited ? (findAnnotation(clazz, this.annotationType) != null) : clazz.isAnnotationPresent(this.annotationType)); } /** * Find a single {@link Annotation} of {@code annotationType} from the supplied {@link Class}, * traversing its interfaces and superclasses if no annotation can be found on the given class itself. * <p>This method explicitly handles class-level annotations which are not declared as * {@link java.lang.annotation.Inherited inherited} <i>as well as annotations on interfaces</i>. * <p>The algorithm operates as follows: Searches for an annotation on the given class and returns * it if found. Else searches all interfaces that the given class declares, returning the annotation * from the first matching candidate, if any. Else proceeds with introspection of the superclass * of the given class, checking the superclass itself; if no annotation found there, proceeds * with the interfaces that the superclass declares. Recursing up through the entire superclass * hierarchy if no match is found. * @param clazz the class to look for annotations on * @param annotationType the annotation class to look for * @return the annotation found, or {@code null} if none found */ public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) { //Assert.notNull(clazz, "Class must not be null"); A annotation = clazz.getAnnotation(annotationType); if (annotation != null) { return annotation; } for (Class<?> ifc : clazz.getInterfaces()) { annotation = findAnnotation(ifc, annotationType); if (annotation != null) { return annotation; } } if (!Annotation.class.isAssignableFrom(clazz)) { for (Annotation ann : clazz.getAnnotations()) { annotation = findAnnotation(ann.annotationType(), annotationType); if (annotation != null) { return annotation; } } } Class<?> superClass = clazz.getSuperclass(); if (superClass == null || superClass == Object.class) { return null; } return findAnnotation(superClass, annotationType); } }