From 7cc09949423ac8e3efa9d859fc7f5603382cd8db Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Thu, 30 Jun 2022 15:31:38 +0800 Subject: [PATCH] =?UTF-8?q?AnnotationUtil=E6=B7=BB=E5=8A=A0scanMetaAnnotat?= =?UTF-8?q?ion=E3=80=81scanClass=E4=B8=8EscanMethod=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotation/AnnotationUtil.java | 91 ++++++++++++++---- .../core/annotation/AnnotationUtilTest.java | 96 ++++++++++++++++++- 2 files changed, 166 insertions(+), 21 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index 0fee2867c..14d160864 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -130,7 +130,7 @@ public class AnnotationUtil { */ public static T[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Class annotationType) { final Annotation[] annotations = getAnnotations(annotationEle, isToCombination, - (annotation -> null == annotationType || annotationType.isAssignableFrom(annotation.getClass()))); + (annotation -> null == annotationType || annotationType.isAssignableFrom(annotation.getClass()))); final T[] result = ArrayUtil.newArray(annotationType, annotations.length); for (int i = 0; i < annotations.length; i++) { @@ -151,7 +151,7 @@ public class AnnotationUtil { */ public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate predicate) { if (null == annotationEle) { - return new Annotation[0]; + return null; } if (isToCombination) { @@ -251,8 +251,8 @@ public class AnnotationUtil { final String name = t.getName(); // 跳过自有的几个方法 return (false == "hashCode".equals(name)) // - && (false == "toString".equals(name)) // - && (false == "annotationType".equals(name)); + && (false == "toString".equals(name)) // + && (false == "annotationType".equals(name)); } return false; }); @@ -288,13 +288,13 @@ public class AnnotationUtil { final Target target = annotationType.getAnnotation(Target.class); if (null == target) { return new ElementType[]{ElementType.TYPE, // - ElementType.FIELD, // - ElementType.METHOD, // - ElementType.PARAMETER, // - ElementType.CONSTRUCTOR, // - ElementType.LOCAL_VARIABLE, // - ElementType.ANNOTATION_TYPE, // - ElementType.PACKAGE// + ElementType.FIELD, // + ElementType.METHOD, // + ElementType.PARAMETER, // + ElementType.CONSTRUCTOR, // + ElementType.LOCAL_VARIABLE, // + ElementType.ANNOTATION_TYPE, // + ElementType.PACKAGE// }; } return target.value(); @@ -352,9 +352,9 @@ public class AnnotationUtil { /** * 将指定注解实例与其元注解转为合成注解 * - * @param annotation 注解 - * @param annotationType 注解类型 - * @param 注解类型 + * @param annotation 注解对象 + * @param annotationType 注解类 + * @param 注解类型 * @return 合成注解 * @see SyntheticAnnotation */ @@ -369,23 +369,74 @@ public class AnnotationUtil { *
  • 若元素是方法、属性或注解,则只解析其直接声明的注解;
  • * * - * @param annotatedElement 可注解元素 - * @param annotationType 注解类型 - * @param 注解类型 - * @return 注解 + * @param annotatedEle {@link AnnotatedElement},可以是Class、Method、Field、Constructor、ReflectPermission + * @param annotationType 注解类 + * @param 注解类型 + * @return 合成注解 * @see SyntheticAnnotation */ - public static List getAllSynthesisAnnotations(AnnotatedElement annotatedElement, Class annotationType) { + public static List getAllSynthesisAnnotations(AnnotatedElement annotatedEle, Class annotationType) { AnnotationScanner[] scanners = new AnnotationScanner[] { new MetaAnnotationScanner(), new TypeAnnotationScanner(), new MethodAnnotationScanner(), new FieldAnnotationScanner() }; - return AnnotationScanner.scanByAnySupported(annotatedElement, scanners).stream() + return AnnotationScanner.scanByAnySupported(annotatedEle, scanners).stream() .map(SyntheticAnnotation::of) .map(annotation -> annotation.getAnnotation(annotationType)) .filter(Objects::nonNull) .collect(Collectors.toList()); } + /** + * 扫描注解类,以及注解类的{@link Class}层级结构中的注解,将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认注解外, + * 按元注解对象与{@code annotationType}的距离和{@link Class#getAnnotations()}顺序排序的注解对象集合 + * + * @param annotationType 注解类 + * @return 注解对象集合 + * @see MetaAnnotationScanner + */ + public static List scanMetaAnnotation(Class annotationType) { + return new MetaAnnotationScanner().getIfSupport(annotationType); + } + + /** + *

    扫描类以及类的{@link Class}层级结构中的注解,将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认元注解外, + * 全部类/接口的{@link Class#getAnnotations()}方法返回的注解对象。
    + * 层级结构将按广度优先递归,遵循规则如下: + *

      + *
    • 同一层级中,优先处理父类,然后再处理父接口;
    • + *
    • 同一个接口在不同层级出现,优先选择层级距离{@code targetClass}更近的接口;
    • + *
    • 同一个接口在相同层级出现,优先选择其子类/子接口被先解析的那个;
    • + *
    + * 注解根据其声明类/接口被扫描的顺序排序,若注解都在同一个{@link Class}中被声明,则还会遵循{@link Class#getAnnotations()}的顺序。 + * + * @param targetClass 类 + * @return 注解对象集合 + * @see TypeAnnotationScanner + */ + public static List scanClass(Class targetClass) { + return new TypeAnnotationScanner().getIfSupport(targetClass); + } + + /** + *

    扫描方法,以及该方法所在类的{@link Class}层级结构中的具有相同方法签名的方法, + * 将返回除了{@link #META_ANNOTATIONS}中指定的JDK默认元注解外, + * 全部匹配方法上{@link Method#getAnnotations()}方法返回的注解对象。
    + * 方法所在类的层级结构将按广度优先递归,遵循规则如下: + *

      + *
    • 同一层级中,优先处理父类,然后再处理父接口;
    • + *
    • 同一个接口在不同层级出现,优先选择层级距离{@code targetClass}更近的接口;
    • + *
    • 同一个接口在相同层级出现,优先选择其子类/子接口被先解析的那个;
    • + *
    + * 方法上的注解根据方法的声明类/接口被扫描的顺序排序,若注解都在同一个类的同一个方法中被声明,则还会遵循{@link Method#getAnnotations()}的顺序。 + * + * @param method 方法 + * @return 注解对象集合 + * @see MethodAnnotationScanner + */ + public static List scanMethod(Method method) { + return new MethodAnnotationScanner(true).getIfSupport(method); + } + /** * 方法是否为注解属性方法。
    * 方法无参数,且有返回值的方法认为是注解属性的方法。 diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java index 167b62d2c..a47fc9712 100755 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java @@ -1,9 +1,14 @@ package cn.hutool.core.annotation; +import cn.hutool.core.util.ReflectUtil; import org.junit.Assert; import org.junit.Test; -import java.lang.annotation.Annotation; +import java.lang.annotation.*; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Collections; +import java.util.List; public class AnnotationUtilTest { @@ -46,4 +51,93 @@ public class AnnotationUtilTest { } } + + @Test + public void scanMetaAnnotationTest() { + // RootAnnotation -> RootMetaAnnotation1 -> RootMetaAnnotation2 -> RootMetaAnnotation3 + // -> RootMetaAnnotation3 + List annotations = AnnotationUtil.scanMetaAnnotation(RootAnnotation.class); + Assert.assertEquals(4, annotations.size()); + Assert.assertEquals(RootMetaAnnotation3.class, annotations.get(0).annotationType()); + Assert.assertEquals(RootMetaAnnotation1.class, annotations.get(1).annotationType()); + Assert.assertEquals(RootMetaAnnotation2.class, annotations.get(2).annotationType()); + Assert.assertEquals(RootMetaAnnotation3.class, annotations.get(3).annotationType()); + } + + @Test + public void scanClassTest() { + // TargetClass -> TargetSuperClass ----------------------------------> SuperInterface + // -> TargetSuperInterface -> SuperTargetSuperInterface -> SuperInterface + List annotations = AnnotationUtil.scanClass(TargetClass.class); + Assert.assertEquals(5, annotations.size()); + Assert.assertEquals("TargetClass", ((AnnotationForTest)annotations.get(0)).value()); + Assert.assertEquals("TargetSuperClass", ((AnnotationForTest)annotations.get(1)).value()); + Assert.assertEquals("TargetSuperInterface", ((AnnotationForTest)annotations.get(2)).value()); + Assert.assertEquals("SuperInterface", ((AnnotationForTest)annotations.get(3)).value()); + Assert.assertEquals("SuperTargetSuperInterface", ((AnnotationForTest)annotations.get(4)).value()); + } + + @Test + public void scanMethodTest() { + // TargetClass -> TargetSuperClass + // -> TargetSuperInterface + Method method = ReflectUtil.getMethod(TargetClass.class, "testMethod"); + Assert.assertNotNull(method); + List annotations = AnnotationUtil.scanMethod(method); + Assert.assertEquals(3, annotations.size()); + Assert.assertEquals("TargetClass", ((AnnotationForTest)annotations.get(0)).value()); + Assert.assertEquals("TargetSuperClass", ((AnnotationForTest)annotations.get(1)).value()); + Assert.assertEquals("TargetSuperInterface", ((AnnotationForTest)annotations.get(2)).value()); + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface RootMetaAnnotation3 {} + + @RootMetaAnnotation3 + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.ANNOTATION_TYPE) + public @interface RootMetaAnnotation2 {} + + @RootMetaAnnotation2 + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.ANNOTATION_TYPE) + public @interface RootMetaAnnotation1 {} + + @RootMetaAnnotation3 + @RootMetaAnnotation1 + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE_USE) + public @interface RootAnnotation {} + + @AnnotationForTest("TargetClass") + static class TargetClass extends TargetSuperClass implements TargetSuperInterface { + + @Override + @AnnotationForTest("TargetClass") + public List testMethod() { return Collections.emptyList(); } + + } + + @AnnotationForTest("TargetSuperClass") + static class TargetSuperClass implements SuperInterface { + + @AnnotationForTest("TargetSuperClass") + public Collection testMethod() { return Collections.emptyList(); } + + } + + @AnnotationForTest("TargetSuperInterface") + interface TargetSuperInterface extends SuperTargetSuperInterface { + + @AnnotationForTest("TargetSuperInterface") + Object testMethod(); + + } + + @AnnotationForTest("SuperTargetSuperInterface") + interface SuperTargetSuperInterface extends SuperInterface{} + + @AnnotationForTest("SuperInterface") + interface SuperInterface{} + }