All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.datalking.util.AnnotationUtils Maven / Gradle / Ivy

The newest version!

package com.github.datalking.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


public abstract class AnnotationUtils {

    public static final String VALUE = "value";

    private static final String REPEATABLE_CLASS_NAME = "java.lang.annotation.Repeatable";

    private static final Map findAnnotationCache =
            new ConcurrentHashMap(256);

    private static final Map metaPresentCache =
            new ConcurrentHashMap(256);

    private static final Map, Boolean> annotatedInterfaceCache =
            new ConcurrentHashMap, Boolean>(256);

    private static final Map, Boolean> synthesizableCache =
            new ConcurrentHashMap, Boolean>(256);

    private static final Map, Map>> attributeAliasesCache =
            new ConcurrentHashMap, Map>>(256);

    private static final Map, List> attributeMethodsCache =
            new ConcurrentHashMap, List>(256);


    public static  A findAnnotation(Method method, Class annotationType) {
        Assert.notNull(method, "Method must not be null");
        if (annotationType == null) {
            return null;
        }

        AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
        A result = (A) findAnnotationCache.get(cacheKey);

        if (result == null) {
//            Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
            result = findAnnotation((AnnotatedElement) method, annotationType);

            if (result == null) {
                result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());
            }

            Class clazz = method.getDeclaringClass();
            while (result == null) {
                clazz = clazz.getSuperclass();
                if (clazz == null || Object.class == clazz) {
                    break;
                }
                try {
                    Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
//                    Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
                    result = findAnnotation((AnnotatedElement) equivalentMethod, annotationType);
                } catch (NoSuchMethodException ex) {
                    // No equivalent method found
                }
                if (result == null) {
                    result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
                }
            }

            if (result != null) {
                findAnnotationCache.put(cacheKey, result);
            }
        }

        return result;
    }

    public static  A findAnnotation(AnnotatedElement annotatedElement, Class annotationType) {
        Assert.notNull(annotatedElement, "AnnotatedElement must not be null");
        if (annotationType == null) {
            return null;
        }

        A ann = findAnnotation(annotatedElement, annotationType, new HashSet<>());
        return ann;
    }

    private static  A findAnnotation(AnnotatedElement annotatedElement, Class annotationType, Set visited) {
        try {
            Annotation[] anns = annotatedElement.getDeclaredAnnotations();
            for (Annotation ann : anns) {
                if (ann.annotationType() == annotationType) {
                    return (A) ann;
                }
            }
            for (Annotation ann : anns) {
                if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
                    A annotation = findAnnotation((AnnotatedElement) ann.annotationType(), annotationType, visited);
                    if (annotation != null) {
                        return annotation;
                    }
                }
            }
        } catch (Throwable ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
        return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType()));
    }

    static boolean isInJavaLangAnnotationPackage(Class annotationType) {
        return (annotationType != null && isInJavaLangAnnotationPackage(annotationType.getName()));
    }

    public static boolean isInJavaLangAnnotationPackage(String annotationType) {
        return (annotationType != null && annotationType.startsWith("java.lang.annotation"));
    }


    private static  A searchOnInterfaces(Method method, Class 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;
    }

    static boolean isInterfaceWithAnnotatedMethods(Class iface) {
        Boolean found = annotatedInterfaceCache.get(iface);
        if (found != null) {
            return found;
        }
        found = Boolean.FALSE;
        for (Method ifcMethod : iface.getMethods()) {
            try {
                if (ifcMethod.getAnnotations().length > 0) {
                    found = Boolean.TRUE;
                    break;
                }
            } catch (Throwable ex) {
                ex.printStackTrace();
            }
        }
        annotatedInterfaceCache.put(iface, found);
        return found;
    }


    public static  A getAnnotation(Method method, Class annotationType) {
//        Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
        return getAnnotation((AnnotatedElement) method, annotationType);
    }

    public static  A getAnnotation(AnnotatedElement annotatedElement, Class annotationType) {
        try {
            A annotation = annotatedElement.getAnnotation(annotationType);
            if (annotation == null) {
                for (Annotation metaAnn : annotatedElement.getAnnotations()) {
                    annotation = metaAnn.annotationType().getAnnotation(annotationType);
                    if (annotation != null) {
                        break;
                    }
                }
            }
            return annotation;
        } catch (Throwable ex) {
            ex.printStackTrace();
            return null;
        }
    }

    private static final class AnnotationCacheKey implements Comparable {

        private final AnnotatedElement element;

        private final Class annotationType;

        public AnnotationCacheKey(AnnotatedElement element, Class annotationType) {
            this.element = element;
            this.annotationType = annotationType;
        }

        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (!(other instanceof AnnotationCacheKey)) {
                return false;
            }
            AnnotationCacheKey otherKey = (AnnotationCacheKey) other;
            return (this.element.equals(otherKey.element) && this.annotationType.equals(otherKey.annotationType));
        }

        @Override
        public int hashCode() {
            return (this.element.hashCode() * 29 + this.annotationType.hashCode());
        }

        @Override
        public String toString() {
            return "@" + this.annotationType + " on " + this.element;
        }

        @Override
        public int compareTo(AnnotationCacheKey other) {
            int result = this.element.toString().compareTo(other.element.toString());
            if (result == 0) {
                result = this.annotationType.getName().compareTo(other.annotationType.getName());
            }
            return result;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy