From 254e6f5315852aab9b0354d756ef5420fa9aba82 Mon Sep 17 00:00:00 2001
From: huangchengxing <841396397@qq.com>
Date: Tue, 5 Jul 2022 16:03:11 +0800
Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E5=90=88=E6=88=90=E6=B3=A8=E8=A7=A3?=
=?UTF-8?q?=E4=BB=A3=E7=90=86=E7=B1=BB=E6=8F=90=E5=8F=96=E4=B8=BA=E5=A4=96?=
=?UTF-8?q?=E9=83=A8=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../core/annotation/SyntheticAnnotation.java | 14 +-
.../annotation/SyntheticAnnotationProxy.java | 143 ++++++++++++++++++
.../annotation/SyntheticMetaAnnotation.java | 115 ++------------
.../SyntheticMetaAnnotationTest.java | 6 +-
4 files changed, 174 insertions(+), 104 deletions(-)
create mode 100644 hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java
index 4718ea857..084c12566 100644
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotation.java
@@ -6,6 +6,7 @@ import java.lang.reflect.AnnotatedElement;
/**
* 表示基于特定规则聚合的一组注解
*
+ * @param 合成注解类型
* @author huangchengxing
*/
public interface SyntheticAnnotation> extends Annotation, AnnotatedElement {
@@ -24,6 +25,15 @@ public interface SyntheticAnnotation> extends
*/
SynthesizedAnnotationAttributeProcessor getAttributeProcessor();
+ /**
+ * 获取已合成的注解
+ *
+ * @param annotationType 注解类型
+ * @param 注解类型
+ * @return 已合成的注解
+ */
+ SynthesizedAnnotation getSynthesizedAnnotation(Class annotationType);
+
/**
* 获取当前的注解类型
*
@@ -38,6 +48,7 @@ public interface SyntheticAnnotation> extends
* 获取指定注解对象
*
* @param annotationType 注解类型
+ * @param 注解类型
* @return 注解对象
*/
@Override
@@ -64,6 +75,7 @@ public interface SyntheticAnnotation> extends
* 获取合成注解
*
* @param annotationType 注解类型
+ * @param 注解类型
* @return 类型
*/
T syntheticAnnotation(Class annotationType);
@@ -80,8 +92,8 @@ public interface SyntheticAnnotation> extends
/**
* 基于指定根注解,构建包括其元注解在内的合成注解
*
- * @param 注解类型
* @param rootAnnotation 根注解
+ * @param 注解类型
* @return 合成注解
*/
static SyntheticAnnotation of(T rootAnnotation) {
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java
new file mode 100644
index 000000000..101835f47
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticAnnotationProxy.java
@@ -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 代理的注解类型
+ * @author huangchengxing
+ */
+class SyntheticAnnotationProxy implements InvocationHandler {
+
+ private final SyntheticAnnotation> syntheticAnnotation;
+ private final SynthesizedAnnotation annotation;
+ private final Map> methods;
+
+ SyntheticAnnotationProxy(SyntheticAnnotation> syntheticAnnotation, SynthesizedAnnotation annotation) {
+ this.syntheticAnnotation = syntheticAnnotation;
+ this.annotation = annotation;
+ this.methods = new HashMap<>(9);
+ loadMethods();
+ }
+
+ /**
+ * 创建一个代理注解,生成的代理对象将是{@link SyntheticProxyAnnotation}与指定的注解类的子类。
+ *
+ * - 当作为{@code annotationType}所指定的类型使用时,其属性将通过合成它的{@link SyntheticAnnotation}获取;
+ * - 当作为{@link SyntheticProxyAnnotation}或{@link SynthesizedAnnotation}使用时,将可以获得原始注解实例的相关信息;
+ *
+ *
+ * @param annotationType 注解类型
+ * @param syntheticAnnotation 合成注解
+ * @param 代理的注解类型
+ * @return 代理注解
+ */
+ @SuppressWarnings("unchecked")
+ static A create(
+ Class annotationType, SyntheticAnnotation> syntheticAnnotation) {
+ final SynthesizedAnnotation annotation = syntheticAnnotation.getSynthesizedAnnotation(annotationType);
+ final SyntheticAnnotationProxy 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> extends SynthesizedAnnotation {
+
+ /**
+ * 获取该注解所属的合成注解
+ *
+ * @return 合成注解
+ */
+ SyntheticAnnotation getSyntheticAnnotation();
+
+ /**
+ * 获取该代理注解对应的已合成注解
+ *
+ * @return 理注解对应的已合成注解
+ */
+ SynthesizedAnnotation getSynthesizedAnnotation();
+
+ }
+
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticMetaAnnotation.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticMetaAnnotation.java
index 8fadd3261..708fc8fe1 100644
--- a/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticMetaAnnotation.java
+++ b/hutool-core/src/main/java/cn/hutool/core/annotation/SyntheticMetaAnnotation.java
@@ -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 implements SyntheticA
return null;
}
+ /**
+ * 获取已合成的注解
+ *
+ * @param annotationType 注解类型
+ * @return 已合成的注解
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public SynthesizedAnnotation getSynthesizedAnnotation(Class annotationType) {
+ return (SynthesizedAnnotation)metaAnnotationMap.get(annotationType);
+ }
+
/**
* 获取根注解类型
*
@@ -212,18 +218,11 @@ public class SyntheticMetaAnnotation implements SyntheticA
*
* @param annotationType 注解类型
* @return 合成注解对象
+ * @see SyntheticAnnotationProxy#create(Class, SyntheticAnnotation)
*/
- @SuppressWarnings("unchecked")
@Override
public T syntheticAnnotation(Class 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 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 implements SyntheticA
}
- /**
- * 表示一个已经被合成的注解
- *
- * @author huangchengxing
- */
- interface Synthesized {
-
- /**
- * 获取合成注解中已解析的元注解信息
- *
- * @return 合成注解中已解析的元注解信息
- */
- Map, MetaAnnotation> getMetaAnnotationMap();
-
- static boolean isMetaAnnotationMapMethod(Method method) {
- return StrUtil.equals("getMetaAnnotationMap", method.getName());
- }
-
- }
-
- /**
- * 合成注解代理类
- *
- * @author huangchengxing
- */
- static class SyntheticAnnotationProxy implements Annotation, InvocationHandler {
-
- private final Class annotationType;
- private final SyntheticMetaAnnotation> syntheticMetaAnnotation;
-
- public SyntheticAnnotationProxy(SyntheticMetaAnnotation> syntheticMetaAnnotation, Class 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());
- }
-
- }
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticMetaAnnotationTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticMetaAnnotationTest.java
index 002311593..e85862be9 100644
--- a/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticMetaAnnotationTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/annotation/SyntheticMetaAnnotationTest.java
@@ -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));
}
// 注解结构如下: