Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 函数从调用堆栈中检索最顶层的注释_Java_Testing_Annotations_Automated Tests_Java Annotations - Fatal编程技术网

Java 函数从调用堆栈中检索最顶层的注释

Java 函数从调用堆栈中检索最顶层的注释,java,testing,annotations,automated-tests,java-annotations,Java,Testing,Annotations,Automated Tests,Java Annotations,我想定义一个抽象基类,它定义了在测试各种API时要反复实现的通用可重用测试用例。我的想法是定义一次测试,然后我可以继承通用测试以获得测试定义,我的测试代码所要做的就是实现如何执行测试的细节。这样我就不会错过好的测试用例,当我想到另一个好的测试用例进行测试时,我不必重新发明轮子,也不必在几十个地方进行更改 本质上,我正在进行参数化测试,其中参数是在基类中定义的。预期结果也在基类中定义。但是,有时需要覆盖预期结果。例如,普通字符串字段可能允许任何字符,而对象名称字段可能(或在我的情况下)限制哪些字符

我想定义一个抽象基类,它定义了在测试各种API时要反复实现的通用可重用测试用例。我的想法是定义一次测试,然后我可以继承通用测试以获得测试定义,我的测试代码所要做的就是实现如何执行测试的细节。这样我就不会错过好的测试用例,当我想到另一个好的测试用例进行测试时,我不必重新发明轮子,也不必在几十个地方进行更改

本质上,我正在进行参数化测试,其中参数是在基类中定义的。预期结果也在基类中定义。但是,有时需要覆盖预期结果。例如,普通字符串字段可能允许任何字符,而对象名称字段可能(或在我的情况下)限制哪些字符是合法的。例如,字符串字段允许值中有“?”,而名称字段不允许

我试图找到一种干净的方法,在基类中定义一次参数,只定义一次预期结果,但可以在上下文需要的实现类中重写它

我遇到的问题是,当重写方法时,必须替换其实现。你不能只更换一部分。我希望在不重写参数部分的情况下替换预期结果。我也不认为把每个测试分解成两种方法,一种是提供参数的方法,另一种是定义预期行为的方法。 我正在考虑的一个选择是使用注释来定义预期的结果。然后我可以重写注释,然后将实现委托给基类实现。只要基类使用注释来决定行为,它就应该工作

例如:(在伪代码中,不是真正的Java)

考虑到这种层次结构,
foo.test1()
bar.test1()
baz.test1()
都做了完全相同的事情。而
foo.test2()
做一件事,而
bar.test2()
baz.test2()
做其他事情。类似地,
foo.test3()
bar.test3()
做一件事,但是
baz.test3()
会有所不同

我可以使用注释来完成此行为吗?如果是这样的话,
isFubar
会是什么样子?我还没有看到这种方法名称未知的反射示例


作为补充说明,如果有一种更干净的方法来完成预期的行为,我很乐意听到它是什么。

要在调用堆栈中找到最早的匹配注释,可以使用如下函数:

static <T extends Annotation> T seekAnnotation(Class<T> annotationClass) {
    T annotation = null;
    try {
        for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
            T found = seekAnnotation(annotationClass, ste);
            if (found != null) {
                annotation = found;
            }
        }
    } catch (Exception e) {
        //
    }
    return annotation;
}

static <T extends Annotation> T seekAnnotation(Class<T> annotationClass, StackTraceElement ste) {
    T annotation = null;
    try {
        Class<?> claz = Class.forName(ste.getClassName());
        Method method = claz.getDeclaredMethod(ste.getMethodName());
        annotation = method.getAnnotation(annotationClass);
    } catch (Exception e) {
        //
    }
    return annotation;
}

闻起来可能是XY问题。您可能希望研究AOP,或者尝试找到一种更面向对象的方法。请详细说明您试图实现的目标,而不是如何实现。根据您的代码片段,只需覆盖
isFubar()
以返回true或false,并完全放弃注释,这将更有意义。此外,您提出的问题会被视为代码请求,这在这里是不受欢迎的。你有没有试图解决这个问题?如果您希望基类提供一个值,并且希望子类选择性地重写该值,并且希望该值可用于基类方法,那么只需声明一个
受保护的
方法,返回所需的值,并使基类返回其值,子类可以重写该方法并返回其他内容(如果需要)。跳出圈套,试图模仿使用注释的非常常见的行为只是。。。错误。类
foo
中的
doThis
doThat
方法必须声明为
abstract
。在Java中,不能将参数声明为
void
。Java命名约定是以大写字母开头的类名。不幸的是,在这个例子中,事情过于简单了。无论哪个方法有注释,
isFubar
的定义都需要起作用。因为类中可能有50-100个具有注释的方法。这就是我提到遍历调用堆栈的原因。这是遍历堆栈跟踪的第二个版本。很好!看起来,除非它在循环时出错,否则它将获取调用堆栈中最高的注释值,这正是我想要的。它能够做到这一点,而不必知道具体的方法名称,这是我不清楚如何做到的。我将把这一点作为我问题的答案。不过,我很好奇:需要添加哪些内容才能使其更加健壮?(不是问代码,只是想知道你在想什么)一个问题是,如果你的方法签名有参数,那么你必须做更多的工作才能在类中找到方法。getDeclaredMethods方法还包含一个参数类列表,因此我的代码永远不会遇到参数化方法,可以使用getDeclaredMethods(),但如果得到多个结果,则不知道实际调用了哪个方法。我脑子里没有其他具体的例子,但我怀疑还有其他问题。根据您的用例,这些可能是无关的。
static <T extends Annotation> T seekAnnotation(Class<T> annotationClass) {
    T annotation = null;
    try {
        for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
            T found = seekAnnotation(annotationClass, ste);
            if (found != null) {
                annotation = found;
            }
        }
    } catch (Exception e) {
        //
    }
    return annotation;
}

static <T extends Annotation> T seekAnnotation(Class<T> annotationClass, StackTraceElement ste) {
    T annotation = null;
    try {
        Class<?> claz = Class.forName(ste.getClassName());
        Method method = claz.getDeclaredMethod(ste.getMethodName());
        annotation = method.getAnnotation(annotationClass);
    } catch (Exception e) {
        //
    }
    return annotation;
}
boolean isFubar() {
    return seekAnnotation(fubar.class).value();
}