/*
* Copyright 2011 Blazebit
*/
package com.blazebit.annotation;
import com.blazebit.reflection.ReflectionUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Utillity class for annotation handling. Basically this class only uses
* java.lang classes for the methods. The only exception is, that #
* javax.enterprise.inject.Stereotype is used for annotation 'inheritance'.
*
* @author Christian Beikov
* @since 0.1.2
*/
@SuppressWarnings("unchecked")
public final class AnnotationUtils {
private static Class<? extends Annotation> stereotypeAnnotationClass;
static {
try {
stereotypeAnnotationClass = (Class<? extends Annotation>) Class
.forName("javax.enterprise.inject.Stereotype");
} catch (ClassNotFoundException ex) {
Logger log = Logger.getLogger(AnnotationUtils.class.getName());
log.log(Level.WARNING, "Stereotype annotation can not be found, skipping annotation inheritance via stereotype.");
}
}
private AnnotationUtils() {
}
/**
* Returns all annotations of a class, also the annotations of the super
* classes, implemented interfaces and the annotations that are present in
* stereotype annotations. The stereotype annotation will not be included in
* the annotation set.
*
* Note that the set can contain annotation objects of the same type with
* different values for their members.
*
* @param clazz
* the class from which to get the annotations
* @return all annotations that are present for the given class
*/
public static Set<Annotation> getAllAnnotations(Class<?> clazz) {
Set<Annotation> annotationSet = new LinkedHashSet<Annotation>();
List<Class<?>> annotationTypes = new ArrayList<Class<?>>();
// Iterate through all super types of the given class
for (Class<?> type : ReflectionUtils.getSuperTypes(clazz)) {
Annotation[] annotations = type.getAnnotations();
// Iterate through all annotations of the current class
for (Annotation a : annotations) {
// Add the current annotation to the result and to the
// annotation types that needed to be examained for stereotype
// annotations
annotationSet.add(a);
annotationTypes.add(a.annotationType());
}
}
while (!annotationTypes.isEmpty()) {
Class<?> annotationType = annotationTypes.remove(annotationTypes.size() - 1);
if (stereotypeAnnotationClass != null
&& annotationType
.isAnnotationPresent(stereotypeAnnotationClass)) {
// If the stereotype annotation is present examaine the
// 'inherited' annotations
for (Annotation annotation : annotationType.getAnnotations()) {
// add the 'inherited' annotations to be examined for
// further stereotype annotations
annotationTypes.add(annotation.annotationType());
if (!annotation.annotationType().equals(
stereotypeAnnotationClass)) {
// add the stereotyped annotations to the set
annotationSet.add(annotation);
}
}
}
}
return annotationSet;
}
/**
* Returns all annotations of a class, also the annotations of the super
* classes, implemented interfaces and the annotations that are present in
* stereotype annotations. The stereotype annotation will not be included in
* the annotation set.
*
* @param m
* the class from which to get the annotations
* @return all annotations that are present for the given class
*/
public static Set<Annotation> getAllAnnotations(Method m) {
Set<Annotation> annotationSet = new LinkedHashSet<Annotation>();
Annotation[] annotations = m.getAnnotations();
List<Class<?>> annotationTypes = new ArrayList<Class<?>>();
// Iterate through all annotations of the current class
for (Annotation a : annotations) {
// Add the current annotation to the result and to the annotation
// types that needed to be examained for stereotype annotations
annotationSet.add(a);
annotationTypes.add(a.annotationType());
}
while (!annotationTypes.isEmpty()) {
Class<?> annotationType = annotationTypes.remove(annotationTypes.size() - 1);
if (stereotypeAnnotationClass != null
&& annotationType
.isAnnotationPresent(stereotypeAnnotationClass)) {
// If the stereotype annotation is present examaine the
// 'inherited' annotations
for (Annotation annotation : annotationType.getAnnotations()) {
// add the 'inherited' annotations to be examined for
// further stereotype annotations
annotationTypes.add(annotation.annotationType());
if (!annotation.annotationType().equals(
stereotypeAnnotationClass)) {
// add the stereotyped annotations to the set
annotationSet.add(annotation);
}
}
}
}
return annotationSet;
}
/**
* Returns the annotation object for the specified annotation class of
* either the method if it can be found, or of the given class object. First
* the annotation is searched via the method
* {@link #findAnnotation(java.lang.reflect.Method, java.lang.Class) }. If
* the annotation can not be found, the method
* {@link #findAnnotation(java.lang.Class, java.lang.Class) } is used to find
* the annotation on class level.
*
* @param <T>
* The annotation type
* @param m
* The method in which to look for the annotation
* @param clazz
* The class in which to look for the annotation if it can not be
* found on method level
* @param annotationClazz
* The type of the annotation to look for
* @return The annotation with the given type if found, otherwise null
*/
public static <T extends Annotation> T findAnnotation(Method m,
Class<?> clazz, Class<T> annotationClazz) {
final T result = findAnnotation(m, annotationClazz);
return result != null ? result : findAnnotation(clazz, annotationClazz);
}
/**
* Returns the annotation object for the specified annotation class of the
* method if it can be found, otherwise null. The annotation is searched in
* the method which and if a stereotype annotation is found, the annotations
* present on an annotation are also examined. If the annotation can not be
* found, null is returned.
*
* @param <T>
* The annotation type
* @param m
* The method in which to look for the annotation
* @param annotationClazz
* The type of the annotation to look for
* @return The annotation with the given type if found, otherwise null
*/
public static <T extends Annotation> T findAnnotation(Method m,
Class<T> annotationClazz) {
List<Class<?>> annotationTypes = new ArrayList<Class<?>>();
// Iterate through all annotations of the current class
for (Annotation a : m.getAnnotations()) {
if (a.annotationType().equals(annotationClazz)) {
return annotationClazz.cast(a);
}
annotationTypes.add(a.annotationType());
}
while (!annotationTypes.isEmpty()) {
Class<?> annotationType = annotationTypes.remove(annotationTypes.size() - 1);
if (stereotypeAnnotationClass != null
&& annotationType
.isAnnotationPresent(stereotypeAnnotationClass)) {
// If the stereotype annotation is present examaine the
// 'inherited' annotations
for (Annotation annotation : annotationType.getAnnotations()) {
if (!annotation.annotationType().equals(
stereotypeAnnotationClass)) {
if (annotation.annotationType().equals(annotationClazz)) {
return annotationClazz.cast(annotation);
}
}
// add the 'inherited' annotations to be examined for
// further stereotype annotations
annotationTypes.add(annotation.annotationType());
}
}
}
return null;
}
/**
* Returns the annotation object for the specified annotation class of the
* given class object. All super types of the given class are examined to
* find the annotation. If a stereotype annotation is found, the annotations
* present on an annotation are also examined.
*
* @param <T>
* The annotation type
* @param clazz
* The class in which to look for the annotation
* @param annotationClazz
* The type of the annotation to look for
* @return The annotation with the given type if found, otherwise null
*/
public static <T extends Annotation> T findAnnotation(Class<?> clazz,
Class<T> annotationClazz) {
List<Class<?>> annotationTypes = new ArrayList<Class<?>>();
// Iterate through all super types of the given class
for (Class<?> type : ReflectionUtils.getSuperTypes(clazz)) {
Annotation[] annotations = type.getAnnotations();
// Iterate through all annotations of the current class
for (Annotation a : annotations) {
if (a.annotationType().equals(annotationClazz)) {
return annotationClazz.cast(a);
}
annotationTypes.add(a.annotationType());
}
}
while (!annotationTypes.isEmpty()) {
Class<?> annotationType = annotationTypes.remove(annotationTypes.size() - 1);
if (stereotypeAnnotationClass != null
&& annotationType
.isAnnotationPresent(stereotypeAnnotationClass)) {
// If the stereotype annotation is present examaine the
// 'inherited' annotations
for (Annotation annotation : annotationType.getAnnotations()) {
if (!annotation.annotationType().equals(
stereotypeAnnotationClass)) {
if (annotation.annotationType().equals(annotationClazz)) {
return annotationClazz.cast(annotation);
}
}
// add the 'inherited' annotations to be examined for
// further stereotype annotations
annotationTypes.add(annotation.annotationType());
}
}
}
return null;
}
}