将合成注解代理类提取为外部类

This commit is contained in:
huangchengxing 2022-07-05 16:03:11 +08:00
parent d20980096e
commit 254e6f5315
4 changed files with 174 additions and 104 deletions

View File

@ -6,6 +6,7 @@ import java.lang.reflect.AnnotatedElement;
/**
* 表示基于特定规则聚合的一组注解
*
* @param <A> 合成注解类型
* @author huangchengxing
*/
public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends Annotation, AnnotatedElement {
@ -24,6 +25,15 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
*/
SynthesizedAnnotationAttributeProcessor<A> getAttributeProcessor();
/**
* 获取已合成的注解
*
* @param annotationType 注解类型
* @param <T> 注解类型
* @return 已合成的注解
*/
<T extends Annotation> SynthesizedAnnotation<T> getSynthesizedAnnotation(Class<T> annotationType);
/**
* 获取当前的注解类型
*
@ -38,6 +48,7 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
* 获取指定注解对象
*
* @param annotationType 注解类型
* @param <T> 注解类型
* @return 注解对象
*/
@Override
@ -64,6 +75,7 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
* 获取合成注解
*
* @param annotationType 注解类型
* @param <T> 注解类型
* @return 类型
*/
<T extends Annotation> T syntheticAnnotation(Class<T> annotationType);
@ -80,8 +92,8 @@ public interface SyntheticAnnotation<A extends SynthesizedAnnotation<?>> extends
/**
* 基于指定根注解构建包括其元注解在内的合成注解
*
* @param <T> 注解类型
* @param rootAnnotation 根注解
* @param <T> 注解类型
* @return 合成注解
*/
static <T extends Annotation> SyntheticAnnotation<SyntheticMetaAnnotation.MetaAnnotation> of(T rootAnnotation) {

View File

@ -0,0 +1,143 @@
package cn.hutool.core.annotation;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 合成注解代理类
*
* @param <A> 代理的注解类型
* @author huangchengxing
*/
class SyntheticAnnotationProxy<A extends Annotation> implements InvocationHandler {
private final SyntheticAnnotation<?> syntheticAnnotation;
private final SynthesizedAnnotation<A> annotation;
private final Map<String, BiFunction<Method, Object[], Object>> methods;
SyntheticAnnotationProxy(SyntheticAnnotation<?> syntheticAnnotation, SynthesizedAnnotation<A> annotation) {
this.syntheticAnnotation = syntheticAnnotation;
this.annotation = annotation;
this.methods = new HashMap<>(9);
loadMethods();
}
/**
* 创建一个代理注解生成的代理对象将是{@link SyntheticProxyAnnotation}与指定的注解类的子类
* <ul>
* <li>当作为{@code annotationType}所指定的类型使用时其属性将通过合成它的{@link SyntheticAnnotation}获取</li>
* <li>当作为{@link SyntheticProxyAnnotation}{@link SynthesizedAnnotation}使用时将可以获得原始注解实例的相关信息</li>
* </ul>
*
* @param annotationType 注解类型
* @param syntheticAnnotation 合成注解
* @param <A> 代理的注解类型
* @return 代理注解
*/
@SuppressWarnings("unchecked")
static <A extends Annotation> A create(
Class<A> annotationType, SyntheticAnnotation<?> syntheticAnnotation) {
final SynthesizedAnnotation<A> annotation = syntheticAnnotation.getSynthesizedAnnotation(annotationType);
final SyntheticAnnotationProxy<A> proxyHandler = new SyntheticAnnotationProxy<>(syntheticAnnotation, annotation);
if (ObjectUtil.isNull(annotation)) {
return null;
}
return (A) Proxy.newProxyInstance(
annotationType.getClassLoader(),
new Class[]{annotationType, SyntheticProxyAnnotation.class},
proxyHandler
);
}
static boolean isProxyAnnotation(Class<?> targetClass) {
return ClassUtil.isAssignable(SyntheticProxyAnnotation.class, targetClass);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return Opt.ofNullable(methods.get(method.getName()))
.map(m -> m.apply(method, args))
.orElseGet(() -> ReflectUtil.invoke(this, method, args));
}
// ========================= 代理方法 =========================
void loadMethods() {
methods.put("toString", (method, args) -> proxyToString());
methods.put("hashCode", (method, args) -> proxyHashCode());
methods.put("getSyntheticAnnotation", (method, args) -> proxyGetSyntheticAnnotation());
methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation());
methods.put("getRoot", (method, args) -> annotation.getRoot());
methods.put("isRoot", (method, args) -> annotation.isRoot());
methods.put("getVerticalDistance", (method, args) -> annotation.getVerticalDistance());
methods.put("getHorizontalDistance", (method, args) -> annotation.getHorizontalDistance());
methods.put("hasAttribute", (method, args) -> annotation.hasAttribute((String)args[0], (Class<?>)args[1]));
methods.put("getAttribute", (method, args) -> annotation.getAttribute((String)args[0]));
methods.put("annotationType", (method, args) -> annotation.annotationType());
for (Method declaredMethod : annotation.getAnnotation().annotationType().getDeclaredMethods()) {
methods.put(declaredMethod.getName(), (method, args) -> proxyAttributeValue(method));
}
}
private String proxyToString() {
final String attributes = Stream.of(annotation.annotationType().getDeclaredMethods())
.filter(AnnotationUtil::isAttributeMethod)
.map(method -> StrUtil.format("{}={}", method.getName(), syntheticAnnotation.getAttribute(method.getName(), method.getReturnType())))
.collect(Collectors.joining(", "));
return StrUtil.format("@{}({})", annotation.annotationType().getName(), attributes);
}
private int proxyHashCode() {
return Objects.hash(syntheticAnnotation, annotation);
}
private Object proxyGetSyntheticAnnotation() {
return syntheticAnnotation;
}
private Object proxyGetSynthesizedAnnotation() {
return annotation;
}
private Object proxyAttributeValue(Method attributeMethod) {
return syntheticAnnotation.getAttribute(attributeMethod.getName(), attributeMethod.getReturnType());
}
/**
* 通过代理类生成的合成注解
*
* @author huangchengxing
*/
interface SyntheticProxyAnnotation<A extends Annotation, T extends SynthesizedAnnotation<?>> extends SynthesizedAnnotation<A> {
/**
* 获取该注解所属的合成注解
*
* @return 合成注解
*/
SyntheticAnnotation<T> getSyntheticAnnotation();
/**
* 获取该代理注解对应的已合成注解
*
* @return 理注解对应的已合成注解
*/
SynthesizedAnnotation<A> getSynthesizedAnnotation();
}
}

View File

@ -6,19 +6,13 @@ import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 表示一个根注解与根注解上的多层元注解合成的注解
@ -147,6 +141,18 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
return null;
}
/**
* 获取已合成的注解
*
* @param annotationType 注解类型
* @return 已合成的注解
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Annotation> SynthesizedAnnotation<T> getSynthesizedAnnotation(Class<T> annotationType) {
return (SynthesizedAnnotation<T>)metaAnnotationMap.get(annotationType);
}
/**
* 获取根注解类型
*
@ -212,18 +218,11 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
*
* @param annotationType 注解类型
* @return 合成注解对象
* @see SyntheticAnnotationProxy#create(Class, SyntheticAnnotation)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Annotation> T syntheticAnnotation(Class<T> annotationType) {
if (metaAnnotationMap.containsKey(annotationType)) {
return (T) Proxy.newProxyInstance(
annotationType.getClassLoader(),
new Class[]{annotationType, Synthesized.class},
new SyntheticAnnotationProxy<>(this, annotationType)
);
}
return null;
return SyntheticAnnotationProxy.create(annotationType, this);
}
/**
@ -240,11 +239,7 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
* 广度优先遍历并缓存该根注解上的全部元注解
*/
private void loadMetaAnnotations() {
// 若该注解已经是合成注解则直接使用已解析好的元注解信息
if (source instanceof SyntheticMetaAnnotation.Synthesized) {
this.metaAnnotationMap.putAll(((Synthesized) source).getMetaAnnotationMap());
return;
}
Assert.isFalse(SyntheticAnnotationProxy.isProxyAnnotation(source.getClass()), "source [{}] has been synthesized");
// 扫描元注解
metaAnnotationMap.put(source.annotationType(), new MetaAnnotation(source, source, 0, 0));
new MetaAnnotationScanner().scan(
@ -366,84 +361,4 @@ public class SyntheticMetaAnnotation<A extends Annotation> implements SyntheticA
}
/**
* 表示一个已经被合成的注解
*
* @author huangchengxing
*/
interface Synthesized {
/**
* 获取合成注解中已解析的元注解信息
*
* @return 合成注解中已解析的元注解信息
*/
Map<Class<? extends Annotation>, MetaAnnotation> getMetaAnnotationMap();
static boolean isMetaAnnotationMapMethod(Method method) {
return StrUtil.equals("getMetaAnnotationMap", method.getName());
}
}
/**
* 合成注解代理类
*
* @author huangchengxing
*/
static class SyntheticAnnotationProxy<A extends Annotation> implements Annotation, InvocationHandler {
private final Class<A> annotationType;
private final SyntheticMetaAnnotation<?> syntheticMetaAnnotation;
public SyntheticAnnotationProxy(SyntheticMetaAnnotation<?> syntheticMetaAnnotation, Class<A> annotationType) {
this.syntheticMetaAnnotation = syntheticMetaAnnotation;
this.annotationType = annotationType;
}
@Override
public Class<? extends Annotation> annotationType() {
return annotationType;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Synthesized.isMetaAnnotationMapMethod(method)) {
return syntheticMetaAnnotation.getMetaAnnotationMap();
}
if (ReflectUtil.isHashCodeMethod(method)) {
return getHashCode();
}
if (ReflectUtil.isToStringMethod(method)) {
return getToString();
}
return ObjectUtil.defaultIfNull(
syntheticMetaAnnotation.getAttribute(method.getName(), method.getReturnType()),
() -> ReflectUtil.invoke(this, method, args)
);
}
/**
* 获取toString值
*
* @return toString值
*/
private String getToString() {
final String attributes = Stream.of(annotationType().getDeclaredMethods())
.filter(AnnotationUtil::isAttributeMethod)
.map(method -> StrUtil.format("{}={}", method.getName(), syntheticMetaAnnotation.getAttribute(method.getName(), method.getReturnType())))
.collect(Collectors.joining(", "));
return StrUtil.format("@{}({})", annotationType().getName(), attributes);
}
/**
* 获取hashcode值
*
* @return hashcode值
*/
private int getHashCode() {
return Objects.hash((Object) syntheticMetaAnnotation.getAnnotations());
}
}
}

View File

@ -35,21 +35,21 @@ public class SyntheticMetaAnnotationTest {
Assert.assertEquals("Child!", childAnnotation.childValue());
Assert.assertEquals("Child!", childAnnotation.childValueAlias());
Assert.assertEquals(childAnnotation.grandParentType(), Integer.class);
Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(childAnnotation).getMetaAnnotationMap());
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation<>(childAnnotation));
ParentAnnotation parentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ParentAnnotation.class);
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class));
Assert.assertNotNull(parentAnnotation);
Assert.assertEquals("Child's Parent!", parentAnnotation.parentValue());
Assert.assertEquals("java.lang.Void", parentAnnotation.grandParentType());
Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(parentAnnotation).getMetaAnnotationMap());
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation<>(parentAnnotation));
GrandParentAnnotation grandParentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(GrandParentAnnotation.class);
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
Assert.assertNotNull(grandParentAnnotation);
Assert.assertEquals("Child's GrandParent!", grandParentAnnotation.grandParentValue());
Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class);
Assert.assertEquals(annotationMap, new SyntheticMetaAnnotation<>(grandParentAnnotation).getMetaAnnotationMap());
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation<>(grandParentAnnotation));
}
// 注解结构如下