java - 如何从另一个类获取调用者方法的注释

标签 java reflection java-8 annotations stack-trace

我正在使用jdk1.8.0_221我想根据调用两种不同类型的方法在父类(super class)的构造函数中加载特定配置。我正在寻找最佳实践,最好是一种方便的方法。

为了简化,我将代码情况模拟如下:

package test;
public class A extends Z{
    @Test
    @Marker1
    public void f1() {
        Z.g();
    }
    @Test
    @Marker2
    public void f2() {
        Z.g();
    }
}

package test;
public class B extends Z{
    @Test
    @Marker1
    public void f3() {
        Z.g();
    }
    @Test
    @Marker2
    public void f4() {
        Z.g();
    }
}

package core;
public class Z{
    public Z() {
        //I want to determine here that which type of method calls this constructor
        //The caller could be Marker1 or Marker2
        //And based on the caller, load the corresponding configuration
    }
    public static void g(){
        //some code goes here
    }
}

注意1:来自不同类的许多方法调用 Z.g() ,所以我无法使用类的显式名称来获取方法及其注释。

注意2:所有配置都应该在Z的父类(super class)的构造函数中完成。

注3:g()方法不一定是静态的。

我尝试过以下代码片段,但是 getMethodName()始终返回<init> :

public Z() throws NoSuchMethodException, ClassNotFoundException{
    StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
    StackTraceElement ste = stElements[3];// or stElements[2]
    Class<?> aClass = Class.forName(ste.getClassName());
    String methodName = ste.getMethodName();
    Method method = aClass.getMethod(methodName);
    Annotation[] annotations = aClass.getAnnotations();
    for (Annotation annotation : annotations) {
        if (annotation.getClass().equals(Marker1.class)) {
             //load conf1
             break;
         } else if (annotation.getClass().equals(Marker2.class)) {
             //load conf2
             break;
         }
     }
}

此外,我在 stackoverflow 和其他社区尝试了很多解决方案,但都无法正常工作。

最佳答案

你得到的结果,准确地告诉你发生了什么。您的方法都没有调用构造函数。

所有方法都具有以下形式

@Test
@MarkerN
public void fX() {
    Z.g();
}

因此它们包含对 static 的调用方法g()Z 。但没有实例化 Z .

相反,您的类(class) ABZ 的子类。由于您没有为它们声明显式构造函数,因此编译器会为它们生成默认构造函数,例如

public class A extends Z {

    public A() {
        super(); // here, the constructor of Z gets called
    }


// the other methods …

}

因此,反射查找将告诉您 Z 的调用的构造函数发生在名为 <init> 的方法内,即A的构造函数,分别是B B 的构造函数.

如果这些方法这样做的话,情况会有所不同new Z().g() ,但这会使依赖于 static 之前执行的构造函数的设计变得可疑。方法调用更糟。

这个问题应该在框架端解决,框架端同时执行这两个操作,实例化 AB并调用方法 f1()f4()在他们。例如。使用 JUnit 5,解决方案如下所示:

package test;

import java.lang.annotation.*;
import java.lang.reflect.AnnotatedElement;
import org.junit.jupiter.api.*;

public class A {
    @BeforeEach
    public void prepare(TestInfo ti) {
        Z.loadConfiguration(ti.getTestMethod().get());
    }
    @Test
    @Marker1
    public void f1() {
        Z.g();
    }
    @Test
    @Marker2
    public void f2() {
        Z.g();
    }
}

class Z {
    public static void loadConfiguration(AnnotatedElement e) {
        if(e.isAnnotationPresent(Marker1.class)) {
            System.out.println("Marker1");
        }
        else if(e.isAnnotationPresent(Marker2.class)) {
            System.out.println("Marker2");
        } 
    }
    public static void g() {
        System.out.println("Z.g()");
    }
}

@Retention(RetentionPolicy.RUNTIME)
@interface Marker1 {}

@Retention(RetentionPolicy.RUNTIME)
@interface Marker2 {}
Marker1
Z.g()
Marker2
Z.g()

关于java - 如何从另一个类获取调用者方法的注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58040218/

相关文章:

c# - Entity Framework 代码优先 GenericTypeArguments

Java 8,Stream - 查找数字总和超过 10 的字符串的数量

java - 如何使用Junit测试对象是否被修改?

java - 如何用 Java 编写一个简单的按键监听器,将输入保存到 .txt 文件中?

Java - 如何导入 'Reflections' 类?

java - 返回动态类的实例

java - ADF session 超时自动重定向而不弹出对话框

java - 如何从 Document 或 Node 创建 InputStream

multithreading - 使用 Spliterator 将 ConcurrentLinkedQueue 分成两半

java - 在 Java 8 中使用 Streams 代替 for 循环