有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在反映使用类的方法时不存在注释。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

即使是这个简单的检查也会返回^{

method.isAnnotationPresent(Email.class)

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

更新

似乎为了检索参数注释,我需要调用method.getParameterAnnotations()。但我不知道注释属于什么问题


共 (2) 个答案

  1. # 1 楼答案

    必须区分Java8类型注释和(自Java5以来)参数注释。关于类型注释,关键的一点是,您必须声明将注释显式用作类型注释的可能性

    考虑下面的例子:

    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()]
    

    类似的问题可能会出现在方法返回类型上。字段类型当为“类型使用”和方法启用注释时。菲尔德

  2. # 2 楼答案

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