package org.hivedb.annotations; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.hivedb.util.Lists; import org.hivedb.util.classgen.ReflectionTools; import org.hivedb.util.functional.Atom; import org.hivedb.util.functional.Filter; import org.hivedb.util.functional.Maps; import org.hivedb.util.functional.Predicate; public class AnnotationHelper { @SuppressWarnings("unchecked") public static<T extends Annotation> T getFirstInstanceOfAnnotation(Class entityClass, Class<T> annotationClass) { Method m = getFirstMethodWithAnnotation(entityClass, annotationClass); return m == null ? null : m.getAnnotation(annotationClass); } @SuppressWarnings("unchecked") public static<T extends Annotation> Method getFirstMethodWithAnnotation(Class entityClass, Class<T> annotationClass) { return Atom.getFirstOrNull(getAllMethodsWithAnnotation(entityClass, annotationClass)); } @SuppressWarnings("unchecked") public static List<Method> getAllMethodsWithAnnotation(Class entityClass, Class annotationClass) { return getAllMethodsWithAnnotations(entityClass, Collections.singleton(annotationClass)); } @SuppressWarnings("unchecked") public static List<Method> getAllMethodsWithAnnotations(Class entityClass, Collection<Class> annotationClasses) { List<Method> methods = Lists.newArrayList(); for(Method method : entityClass.getMethods()) { Method targetMethod = method; if( !method.getDeclaringClass().equals(entityClass)) { try { method.getDeclaringClass().getMethod(method.getName(), method.getParameterTypes()); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } for (Class annotationClass : annotationClasses ) if(targetMethod.getAnnotation(annotationClass) != null) { methods.add(method); break; } } return methods; } @SuppressWarnings("unchecked") public static Map<Annotation, Object> getAllAnnotatedElements(Class clazz) { Map<Annotation, Object> elements = Maps.newHashMap(); for(Annotation a : clazz.getAnnotations()) elements.put(a, clazz); elements.putAll(getAllAnnotatedConstructors(clazz)); elements.putAll(getAllAnnotatedMethods(clazz)); elements.putAll(getAllAnnotatedFields(clazz)); return elements; } @SuppressWarnings("unchecked") public static Map<? extends Annotation, ? extends Object> getAllAnnotatedMethods(Class clazz) { Map<Annotation, Object> elements = Maps.newHashMap(); for(Method m : clazz.getMethods()) for(Annotation a : m.getAnnotations()) elements.put(a, m); return elements; } @SuppressWarnings("unchecked") public static Map<Annotation, Object> getAllAnnotatedConstructors(Class clazz) { Map<Annotation, Object> elements = Maps.newHashMap(); for(Constructor c : clazz.getConstructors()) for(Annotation a : c.getAnnotations()) elements.put(a, c); return elements; } @SuppressWarnings("unchecked") public static Map<? extends Annotation, ? extends Object> getAllAnnotatedFields(Class clazz) { Map<Annotation, Object> elements = Maps.newHashMap(); for(Field f : clazz.getDeclaredFields()) for(Annotation a : f.getAnnotations()) elements.put(a, f); return elements; } @SuppressWarnings("unchecked") public static<T> T getAnnotationDeeply(Class clazz, String property, Class<? extends T> annotationClass) { return getAnnotationDeeply(ReflectionTools.getGetterOfProperty(clazz, property), annotationClass); } @SuppressWarnings("unchecked") public static<T> T getAnnotationDeeply(Method method, Class<? extends T> annotationClass) { if (method.getAnnotation((Class)annotationClass) != null) return (T)method.getAnnotation((Class)annotationClass); final Method ownerMethod = ReflectionTools.getMethodOfOwner(method); Class<T> owner = (Class<T>) ownerMethod.getDeclaringClass(); if (!owner.equals(method.getDeclaringClass())) return (T)ownerMethod.getAnnotation((Class)annotationClass); return null; } @SuppressWarnings("unchecked") public static<T> T getMethodArgumentAnnotationDeeply(Method method, int argumentIndex, final Class<? extends T> annotationClass) { return (T)Filter.grepSingleOrNull( new Predicate<Annotation>() { public boolean f(Annotation annoation) { return ReflectionTools.doesImplementOrExtend(annoation.getClass(), annotationClass); } }, Arrays.asList(method.getParameterAnnotations()[argumentIndex])); } }