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}与指定的注解类的子类。 + * + * + * @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 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)); } // 注解结构如下: