【问题标题】:No annotations present when reflecting a method using class.getDeclaredMethod使用 class.getDeclaredMethod 反映方法时不存在注释
【发布时间】:2016-09-30 03:36:22
【问题描述】:

我正在使用 reflection 编写一些单元测试,但在从方法参数中检索注释时遇到问题。

我声明了这个接口:

private interface Provider {
    void mock(@Email String email);
}

而我正在尝试体现这种方法,如下:

Class stringClass = String.class;
Method method = Provider.class.getDeclaredMethod("mock", String.class);
AnnotatedType annotatedType = method.getAnnotatedParameterTypes()[0];
Annotation annotation = annotatedType.getAnnotation(Annotation.class);

我期望annotation 变量包含@Email 注释的实例,但它的值是null。

即使是这个简单的检查也会返回false:

method.isAnnotationPresent(Email.class)

那么,当反射一个方法时,如何检索特定参数的注释?

更新

看来,为了检索参数注释,我需要调用method.getParameterAnnotations()。但是这样做的问题是我不知道哪些注解属于哪些方法。

【问题讨论】:

标签: java reflection annotations java-8


【解决方案1】:

如果你想让注解在程序执行过程中可见,你需要用@Retention(RetentionPolicy.RUNTIME)注解:

private interface Provider {
    void mock(@Email String email);
}

@Retention(RetentionPolicy.RUNTIME)
public @interface Email{}

@Test
public void test_annotation_existence() throws NoSuchMethodException {

    Method method = Provider.class.getDeclaredMethod("mock", String.class);

    Annotation[] firstParameterAnnotationsArray = method.getParameterAnnotations()[0];
    boolean isAnnotationPresent = isAnnotationPresent(firstParameterAnnotationsArray, Email.class);

    Assert.assertTrue("Annotation not present!", isAnnotationPresent);

}

private boolean isAnnotationPresent(Annotation[] annotationsArray, Class clazz) {
    if (annotationsArray == null)
        throw new IllegalArgumentException("Please pass a non-null array of Annotations.");
    for(int i = 0; i < annotationsArray.length; i++ ) {
        if (annotationsArray[i].annotationType().equals(clazz))
            return true;
    }
    return false;
}

【讨论】:

  • 电子邮件已使用保留注释进行了注释。我应该指出这一点。
  • 请看一下其余的代码。 method.getParameterAnnotations()[0] 不返回 AnnotatedType 而是返回 Annotation 的数组,您可以循环访问。
【解决方案2】:

您必须区分 Java 8 类型注释 和(自 Java 5 起)参数 注释。关于类型注解的关键在于,您必须明确声明将注解用作类型注解的可能性。

考虑以下示例:

public class AnnoTest {
    @Retention(RetentionPolicy.RUNTIME)
    @interface Email {}

    void example(@Email String arg) {}

    public static void main(String[] args) throws ReflectiveOperationException {
        Method method=AnnoTest.class.getDeclaredMethod("example", String.class);
        System.out.println("parameter type annotations:");
        AnnotatedType annotatedType = method.getAnnotatedParameterTypes()[0];
        //Annotation annotation = annotatedType.getAnnotation(Annotation.class);
        System.out.println(Arrays.toString(annotatedType.getAnnotations()));
        System.out.println("parameter annotations:");
        System.out.println(Arrays.toString(method.getParameterAnnotations()[0]));
    }
}

它会打印出来

parameter type annotations:
[]
parameter annotations:
[@AnnoTest$Email()]

在这种情况下,注解是参数的一个属性。

现在将其更改为(注意@Target)

public class AnnoTest {
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @interface Email {}

    void example(@Email String arg) {}

    public static void main(String[] args) throws ReflectiveOperationException {
        Method method=AnnoTest.class.getDeclaredMethod("example", String.class);
        System.out.println("parameter type annotations:");
        AnnotatedType annotatedType = method.getAnnotatedParameterTypes()[0];
        //Annotation annotation = annotatedType.getAnnotation(Annotation.class);
        System.out.println(Arrays.toString(annotatedType.getAnnotations()));
        System.out.println("parameter annotations:");
        System.out.println(Arrays.toString(method.getParameterAnnotations()[0]));
    }
}

将打印出来

parameter type annotations:
[@AnnoTest$Email()]
parameter annotations:
[]

相反。所以现在,注解是参数type的一个特征,即String。从概念上讲,该方法的参数类型现在是@Email String(这似乎是最合乎逻辑的选择,因为它允许声明像List&lt;@Email String&gt; 这样的类型,但是您必须了解这些新类型注释是如何工作的并且它不起作用以及 Java 8 之前的库)。

为参数和类型使用启用注释时必须小心,因为这可能会产生模棱两可的注释。 如果发生这种情况,编译器将记录参数和类型的注释,例如 当您将示例中的目标更改为@Target({ElementType.TYPE_USE, ElementType.PARAMETER})时,它将打印

parameter type annotations:
[@AnnoTest$Email()]
parameter annotations:
[@AnnoTest$Email()]

类似的问题可能会出现在方法返回类型,resp。启用“类型使用”和方法的注释时的字段类型,resp。字段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    • 2019-10-27
    • 1970-01-01
    • 2014-09-04
    相关资源
    最近更新 更多