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

时间:2019-09-21 12:21:31

标签: java reflection java-8 annotations stack-trace

我正在使用jdk1.8.0_221,并且我想基于调用两种不同类型的方法在超类的构造函数中加载特定的配置。我正在寻求最佳实践,最好是一种便捷的方法。

由于简化,我将代码情况模拟为以下代码段:

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的超类的构造函数内完成。

注意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和其他社区中尝试了许多无法正常工作的解决方案。

1 个答案:

答案 0 :(得分:0)

您得到的结果恰好告诉您发生了什么。您的方法都没有调用构造函数。

所有方法的格式均为

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

,因此它们包含对类static的{​​{1}}方法g()的调用。但是没有Z的实例。

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

Z

,因此,反射式查找将告诉您public class A extends Z { public A() { super(); // here, the constructor of Z gets called } // the other methods … } 的构造函数的调用发生在名为Z的方法内,该方法是<init>的构造函数。 A的{​​{1}}构造函数。

如果方法使用B会有所不同,但这会使在B方法调用之前依赖于构造函数执行的可疑设计更加糟糕。

这个问题应该在框架方面解决,即同时实例化new Z().g()static并在其上调用方法AB。例如。使用JUnit 5,解决方案如下所示:

f1()
f4()