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);
}
}