Description

Find a single Annotation of annotationType on the supplied Class , traversing its interfaces, annotations, and superclasses if the annotation is not present on the given class itself.

License

Apache License

Parameter

Parameter Description
clazz the class to look for annotations on
annotationType the type of annotation to look for

Return

the annotation if found, or null if not found

Declaration

public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) 

Method Source Code


//package com.java2s;
/*/*from  ww  w . j  av  a 2 s.c  o m*/
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;

import java.util.*;

public class Main {
    private static final Map<Class<?>, Boolean> annotatedInterfaceCache = new WeakHashMap<Class<?>, Boolean>();

    /**
     * Find a single {@link Annotation} of {@code annotationType} from the supplied
     * {@link Method}, traversing its super methods (i.e., from superclasses and
     * interfaces) if no annotation can be found on the given method itself.
     * <p>Annotations on methods are not inherited by default, so we need to handle
     * this explicitly.
     * @param method the method to look for annotations on
     * @param annotationType the annotation type to look for
     * @return the annotation found, or {@code null} if none
     */
    public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
        A annotation = getAnnotation(method, annotationType);
        Class<?> clazz = method.getDeclaringClass();
        if (annotation == null) {
            annotation = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
        }
        while (annotation == null) {
            clazz = clazz.getSuperclass();
            if (clazz == null || clazz.equals(Object.class)) {
                break;
            }
            try {
                Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
                annotation = getAnnotation(equivalentMethod, annotationType);
            } catch (NoSuchMethodException ex) {
                // No equivalent method found
            }
            if (annotation == null) {
                annotation = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
            }
        }
        return annotation;
    }

    /**
     * Find a single {@link Annotation} of {@code annotationType} on the
     * supplied {@link Class}, traversing its interfaces, annotations, and
     * superclasses if the annotation is not <em>present</em> on the given class
     * itself.
     * <p>This method explicitly handles class-level annotations which are not
     * declared as {@link java.lang.annotation.Inherited inherited} <em>as well
     * as meta-annotations and annotations on interfaces</em>.
     * <p>The algorithm operates as follows:
     * <ol>
     * <li>Search for the annotation on the given class and return it if found.
     * <li>Recursively search through all interfaces that the given class declares.
     * <li>Recursively search through all annotations that the given class declares.
     * <li>Recursively search through the superclass hierarchy of the given class.
     * </ol>
     * <p>Note: in this context, the term <em>recursively</em> means that the search
     * process continues by returning to step #1 with the current interface,
     * annotation, or superclass as the class to look for annotations on.
     * @param clazz the class to look for annotations on
     * @param annotationType the type of annotation to look for
     * @return the annotation if found, or {@code null} if not found
     */
    public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
        return findAnnotation(clazz, annotationType, new HashSet<Annotation>());
    }

    /**
     * Perform the search algorithm for {@link #findAnnotation(Class, Class)},
     * avoiding endless recursion by tracking which annotations have already
     * been <em>visited</em>.
     * @param clazz the class to look for annotations on
     * @param annotationType the type of annotation to look for
     * @param visited the set of annotations that have already been visited
     * @return the annotation if found, or {@code null} if not found
     */
    private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType,
            Set<Annotation> visited) {

        if (isAnnotationDeclaredLocally(annotationType, clazz)) {
            return clazz.getAnnotation(annotationType);
        }
        for (Class<?> ifc : clazz.getInterfaces()) {
            A annotation = findAnnotation(ifc, annotationType, visited);
            if (annotation != null) {
                return annotation;
            }
        }
        for (Annotation ann : clazz.getDeclaredAnnotations()) {
            if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
                A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
                if (annotation != null) {
                    return annotation;
                }
            }
        }
        Class<?> superclass = clazz.getSuperclass();
        if (superclass == null || superclass.equals(Object.class)) {
            return null;
        }
        return findAnnotation(superclass, annotationType, visited);
    }

    public static <T extends Annotation> T getAnnotation(Annotation ann, Class<T> annotationType) {
        if (annotationType.isInstance(ann)) {
            return (T) ann;
        }
        return ann.annotationType().getAnnotation(annotationType);
    }

    public static <T extends Annotation> T getAnnotation(AnnotatedElement ae, Class<T> annotationType) {
        T ann = ae.getAnnotation(annotationType);
        if (ann == null) {
            for (Annotation metaAnn : ae.getAnnotations()) {
                ann = metaAnn.annotationType().getAnnotation(annotationType);
                if (ann != null) {
                    break;
                }
            }
        }
        return ann;
    }

    /**
     * Get a single {@link Annotation} of {@code annotationType} from the supplied {@link Method}.
     * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
     * @param method the method to look for annotations on
     * @param annotationType the annotation type to look for
     * @return the annotations found
     */
    public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
        //Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
        //return getAnnotation((AnnotatedElement) resolvedMethod, annotationType);
        return getAnnotation((AnnotatedElement) method, annotationType);
    }

    private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType,
            Class<?>[] ifcs) {
        A annotation = null;
        for (Class<?> iface : ifcs) {
            if (isInterfaceWithAnnotatedMethods(iface)) {
                try {
                    Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
                    annotation = getAnnotation(equivalentMethod, annotationType);
                } catch (NoSuchMethodException ex) {
                    // Skip this interface - it doesn't have the method...
                }
                if (annotation != null) {
                    break;
                }
            }
        }
        return annotation;
    }

    public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz) {
        boolean declaredLocally = false;
        for (Annotation annotation : clazz.getDeclaredAnnotations()) {
            if (annotation.annotationType().equals(annotationType)) {
                declaredLocally = true;
                break;
            }
        }
        return declaredLocally;
    }

    public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
        return annotation.annotationType().getName().startsWith("java.lang.annotation");
    }

    private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
        synchronized (annotatedInterfaceCache) {
            Boolean flag = annotatedInterfaceCache.get(iface);
            if (flag != null) {
                return flag;
            }
            boolean found = false;
            for (Method ifcMethod : iface.getMethods()) {
                if (ifcMethod.getAnnotations().length > 0) {
                    found = true;
                    break;
                }
            }
            annotatedInterfaceCache.put(iface, found);
            return found;
        }
    }
}

Related

  1. findAnnotation(Class aClass, Class annotationClass)
  2. findAnnotation(Class classy, Class targetAnnotation)
  3. findAnnotation(Class clazz, Class annotationClass, Set> set)
  4. findAnnotation(Class clazz, Class annotationClass)
  5. findAnnotation(Class clazz, Class annotationType)
  6. findAnnotation(Class clazz, Class annotationType)
  7. findAnnotation(Class clazz, Class annotationType)
  8. findAnnotation(Class clazz, Class annotationClass)
  9. findAnnotation(Class clazz, Class annotationClass)