com.github.bingoohuang.westcache.utils.Anns Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of westcache Show documentation
Show all versions of westcache Show documentation
java cache with unified administration
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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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;
}
}