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

com.github.bingoohuang.westcache.utils.Anns Maven / Gradle / Ivy

There is a newer version: 0.0.37
Show newest version
package com.github.bingoohuang.westcache.utils;

import com.github.bingoohuang.westcache.WestCacheable;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.experimental.UtilityClass;
import lombok.val;
import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

/**
 * @author bingoohuang [[email protected]] Created on 2016/12/22.
 */
@UtilityClass
public class Anns {
    public static final String SPECS = "specs";

    public static boolean hasAnnotationInHierarchy(Class annotationClass, Class clazz) {
        if (clazz.isAnnotationPresent(annotationClass)) return true;

        for (val interfaceClass : clazz.getInterfaces()) {
            if (interfaceClass.isAnnotationPresent(annotationClass)) return true;
        }

        return clazz.getSuperclass() != null && hasAnnotationInHierarchy(annotationClass, clazz.getSuperclass());
    }

    @Value @AllArgsConstructor
    public static class MethodAndAnnotationAttributes {
        private Method method;
        private Map annotationAttributes;
    }

    public static MethodAndAnnotationAttributes parseWestCacheable(Method methodInvoked, Class annClass) {
        val methodsInHierarchy = Methods.getAllMethodsInHierarchy(methodInvoked);
        for (val method : methodsInHierarchy) {
            val methodAnn = method.getAnnotation(annClass);
            val declaringClz = method.getDeclaringClass();
            val classAnn = declaringClz.getAnnotation(annClass);

            if (methodAnn != null || classAnn != null) {
                val methodAttrs = getAllAttrs(methodAnn);
                val classAttrs = getAllAttrs(classAnn);
                val mergeMap = mergeMap(classAttrs, methodAttrs);
                return new MethodAndAnnotationAttributes(method, mergeMap);
            }

            val setAnns = Sets.newHashSet();
            val annM = searchAnn(setAnns, method.getAnnotations(), annClass);
            val annC = searchAnn(setAnns, declaringClz.getAnnotations(), annClass);
            if (annM != null || annC != null) {
                val mergeMap = mergeMap(annC, annM);
                return new MethodAndAnnotationAttributes(method, mergeMap);
            }
        }

        return null;
    }

    private static Map mergeMap(
            Map classAttrs,
            Map methodAttrs) {
        Map attrs = Maps.newHashMap();
        if (classAttrs != null) merge(attrs, classAttrs);
        if (methodAttrs != null) merge(attrs, methodAttrs);

        return attrs;
    }

    private static Map searchAnn(
            Set setAnns,
            Annotation[] anns,
            Class annClass) {
        for (val ann : anns) {
            val optionAnn = parseRecursiveAnn(setAnns, ann, annClass);
            if (optionAnn != null) return optionAnn;
        }

        return null;
    }

    public static Map removeAttrs(
            Map map, String... attrs) {
        for (String attr : attrs) {
            map.remove(attr);
        }

        return map;
    }

    public static Map getAllAttrs(Annotation ann) {
        Map attrs = Maps.newHashMap();
        if (ann == null) return attrs;

        for (val method : ann.annotationType().getDeclaredMethods()) {
            Object attr = Envs.invoke(method, ann);
            String value = String.valueOf(attr);
            if (StringUtils.isNotEmpty(value)) {
                attrs.put(method.getName(), value);
            }
        }
        return attrs;
    }

    private static Map parseRecursiveAnn(
            Set setAnns,
            Annotation ann,
            Class annClz) {
        if (ann.toString().startsWith("@java.lang.")) return null;
        if (setAnns.contains(ann)) return null;

        setAnns.add(ann);

        val annotations = ann.annotationType().getAnnotations();
        val annAttrs = checkCurrentAnn(ann, annClz, annotations);
        if (annAttrs != null) return annAttrs;

        return checkInheritAnn(setAnns, ann, annClz, annotations);
    }

    private static Map checkInheritAnn(
            Set setAnns,
            Annotation ann,
            Class annClz,
            Annotation[] annotations) {
        for (val annotation : annotations) {
            val attrs = parseRecursiveAnn(setAnns, annotation, annClz);
            if (attrs == null) continue;

            val thisAttrs = getAllAttrs(ann);
            return merge(attrs, thisAttrs);
        }

        return null;
    }

    private static Map checkCurrentAnn(
            Annotation ann,
            Class annClz,
            Annotation[] annotations) {
        for (val typeAnn : annotations) {
            if (!annClz.isInstance(typeAnn)) continue;

            val annAttrs = getAllAttrs(typeAnn);
            val thisAttrs = getAllAttrs(ann);
            return merge(annAttrs, thisAttrs);
        }
        return null;
    }

    static Joiner.MapJoiner mapJoiner = Joiner.on(';').withKeyValueSeparator('=');

    private static Map merge(Map firstMap,
                                             Map otherMap) {
        String specs1 = firstMap.get(SPECS);
        String specs2 = otherMap.get(SPECS);

        firstMap.putAll(otherMap);
        if (specs1 != null || specs2 != null) {
            val specsMap1 = Specs.parseSpecs(specs1);
            val specsMap2 = Specs.parseSpecs(specs2);
            val treeMap = Maps.newTreeMap();
            treeMap.putAll(specsMap1);
            treeMap.putAll(specsMap2);

            String specsJoin = mapJoiner.join(treeMap);
            firstMap.put(SPECS, specsJoin);
        }

        return firstMap;
    }

    public static boolean isFastWestCacheAnnotated(Class clazz) {
        for (val method : clazz.getMethods()) {
            val attrs = parseWestCacheable(method, WestCacheable.class);
            if (attrs != null) return true;
        }

        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy