使用class.getDeclaredMethod反射方法时不存在注释



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

我声明了这个接口:

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()。但问题是,我不知道什么注释属于什么方法。

如果希望注释在程序执行期间可见,则需要使用@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;
}

您必须区分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:
[]

相反。因此,现在,注释是参数类型的一个特征,即String。从概念上讲,该方法的参数类型现在是@Email String(这似乎是最合乎逻辑的选择,因为它允许声明List<@Email String>之类的类型,但您必须了解这些新的类型注释是如何工作的,而且它不能与Java 8之前的库一起工作)。

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

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

类似的问题可能分别出现在方法返回类型中。分别为"类型使用"和方法启用注释时的字段类型。字段。

相关内容

最新更新