Как получить аннотации метода вызывающего из другого класса - PullRequest
1 голос
/ 21 сентября 2019

Я использую 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 голосов
/ 23 сентября 2019

Результат, который вы получаете, точно говорит вам, что происходит.Ни один из ваших методов не вызывает конструктор.

Все ваши методы имеют форму

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

, поэтому они содержат вызов метода static g() класса Z,Но нет экземпляров Z.

Вместо этого ваши классы A и B являются подклассами Z.Поскольку вы не объявляли для них явные конструкторы, компилятор генерирует для них конструкторы по умолчанию, например

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еще хуже.

Эта проблема должна быть решена на стороне фреймворка, который выполняет оба экземпляра: A и B и вызывает для них методы от 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()
...