001package io.ebean.util;
002
003import java.lang.annotation.Annotation;
004import java.lang.reflect.AnnotatedElement;
005import java.util.Collections;
006import java.util.HashSet;
007import java.util.LinkedHashSet;
008import java.util.Set;
009
010/**
011 * Annotation utility methods to find annotations.
012 */
013public class AnnotationUtil {
014
015  /**
016   * Determine if the supplied {@link Annotation} is defined in the core JDK {@code java.lang.annotation} package.
017   */
018  public static boolean notJavaLang(Annotation annotation) {
019    return !annotation.annotationType().getName().startsWith("java.lang.annotation");
020  }
021
022  /**
023   * Simple get on field or method with no meta-annotations or platform filtering.
024   */
025  public static <A extends Annotation> A get(AnnotatedElement element, Class<A> annotation) {
026    return element.getAnnotation(annotation);
027  }
028
029  /**
030   * Simple has with no meta-annotations or platform filtering.
031   */
032  public static <A extends Annotation> boolean has(AnnotatedElement element, Class<A> annotation) {
033    return get(element, annotation) != null;
034  }
035
036  /**
037   * On class get the annotation - includes inheritance.
038   */
039  public static <A extends Annotation> A typeGet(Class<?> clazz, Class<A> annotationType) {
040    while (clazz != null && clazz != Object.class) {
041      final A val = clazz.getAnnotation(annotationType);
042      if (val != null) {
043        return val;
044      }
045      clazz = clazz.getSuperclass();
046    }
047    return null;
048  }
049
050  /**
051   * On class get all the annotations - includes inheritance.
052   */
053  public static <A extends Annotation> Set<A> typeGetAll(Class<?> clazz, Class<A> annotationType) {
054    Set<A> result = new LinkedHashSet<>();
055    typeGetAllCollect(clazz, annotationType, result);
056    return result;
057  }
058
059  private static <A extends Annotation> void typeGetAllCollect(Class<?> clazz, Class<A> annotationType, Set<A> result) {
060    while (clazz != null && clazz != Object.class) {
061      final A[] annotations = clazz.getAnnotationsByType(annotationType);
062      Collections.addAll(result, annotations);
063      clazz = clazz.getSuperclass();
064    }
065  }
066
067  /**
068   * On class simple check for annotation - includes inheritance.
069   */
070  public static <A extends Annotation> boolean typeHas(Class<?> clazz, Class<A> annotation) {
071    return typeGet(clazz, annotation) != null;
072  }
073
074  /**
075   * Find all the annotations for the filter searching meta-annotations.
076   */
077  public static Set<Annotation> metaFindAllFor(AnnotatedElement element, Set<Class<?>> filter) {
078    Set<Annotation> visited = new HashSet<>();
079    Set<Annotation> result = new LinkedHashSet<>();
080    for (Annotation ann : element.getAnnotations()) {
081      metaAdd(ann, filter, visited, result);
082    }
083    return result;
084  }
085
086  private static void metaAdd(Annotation ann, Set<Class<?>> filter, Set<Annotation> visited, Set<Annotation> result) {
087    if (notJavaLang(ann) && visited.add(ann)) {
088      if (filter.contains(ann.annotationType())) {
089        result.add(ann);
090      } else {
091        for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
092          metaAdd(metaAnn, filter, visited, result);
093        }
094      }
095    }
096  }
097}