Последовательность выполнения методов при помощи анотаций и рефлексии
Помогите пожалуйста разобраться в задании.
Есть класс с набором методов, которые отмечены аннотациями. Аннотации @Test, @BeforeSute и @Aftersute создаем, сами указав в последних двух параметр int value() - для указания приоритета выполнения метода.
Нужно создать класс со статическим методом, который принимает как параметр объект типа Class и запускает методы, отмеченные @Test-аннотацией, при этом метод с аннотацией @BeforeSute выполняется первым, потом метод с @Test, а последний с @Aftersute-аннотацией.
Пока выходит только запуск всех методов, отмеченных @Test. Как сделать так, чтобы методы выполнялись в нужном порядке? Мне советуют добавить их в приоритетную очередь (закомментировал в коде PriorityQueue), но я не пойму, как это сделать.
Ниже привожу свой код.
Класс с методами:
public class ClassTest {
@Test
@AfterSuite(value = 2)
public void load() {
System.out.println(" LOAD method ! ");
}
@Test
public void test() {
System.out.println(" TEST method ! ");
}
@Test
@BeforeSuite(value = 5)
public void print() {
System.out.println(" PRINT method ! ");
}
public void noAnnotation () {
System.out.println(" This method has no annotation ! ");
}
}
Анотации:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BeforeSuite {
int value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterSuite {
int value();
}
И класс запуска методов:
public class TestRunner {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException,
NoSuchMethodException, InstantiationException {
ClassTest classTest = new ClassTest();
Class clazz = classTest.getClass();
start(clazz);
}
public static void start(Class c) throws InvocationTargetException, IllegalAccessException,
NoSuchMethodException, InstantiationException {
Object o = c.getConstructor().newInstance();
Method[] methods = c.getDeclaredMethods();
// Queue<Method> queue = new PriorityQueue<>();
for (Method m : methods){
Annotation[] annotations = m.getDeclaredAnnotations();
for (Annotation a : annotations){
if (a.annotationType().equals(Test.class)){
m.invoke(o);
}
}
}
}
}
Ответы (1 шт):
Получилось так:
public class Main {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException,
NoSuchMethodException, InstantiationException {
start(ClassTest.class);
}
public static <T> void start(Class<T> c) throws InvocationTargetException, IllegalAccessException,
NoSuchMethodException, InstantiationException {
Constructor<T> constructor = c.getDeclaredConstructor();
T o = constructor.newInstance();
Method[] methods = c.getDeclaredMethods();
Queue<Method> queue1 = new PriorityQueue<>(
(m1, m2) -> Integer.compare(m2.getDeclaredAnnotation(BeforeSuite.class).value(),
m1.getDeclaredAnnotation(BeforeSuite.class).value())
);
Queue<Method> queue2 = new PriorityQueue<>(
(m1, m2) -> Integer.compare(m2.getDeclaredAnnotation(Test.class).value(),
m1.getDeclaredAnnotation(Test.class).value())
);
Queue<Method> queue3 = new PriorityQueue<>(
(m1, m2) -> Integer.compare(m2.getDeclaredAnnotation(AfterSuite.class).value(),
m1.getDeclaredAnnotation(AfterSuite.class).value())
);
for (Method method : methods) {
if (method.getDeclaredAnnotation(Test.class) != null) {
if (method.getDeclaredAnnotation(BeforeSuite.class) != null) {
queue1.add(method);
} else if (method.getDeclaredAnnotation(AfterSuite.class) != null) {
queue3.add(method);
} else {
queue2.add(method);
}
}
}
Method m;
while ((m = queue1.poll()) != null) {
m.invoke(o);
}
while ((m = queue2.poll()) != null) {
m.invoke(o);
}
while ((m = queue3.poll()) != null) {
m.invoke(o);
}
}
}
Если я правильно понял вашу задачу, то имеется три очереди:
- для
@BeforeSuite - для
@Test - для
@AfterSuite
Для каждой аннотации создаём очередь с приоритетом, при этом компаратор делаем такой, чтобы он сортировал в обратном порядке, ведь первыми должны выполняться те методы, у которых value() у аннотации больше.
Если у метода есть аннотация @Test, то делаем следующие проверки: если у него есть @BeforeSuite, то помещаем в очередь для неё, если есть @AfterSuite, то для неё, и, наконец, если их нет, то это значит, что есть только @Test, так что помещаем метод в очередь для неё.
Так как компараторы были заданы с самого начала, то методы во всех очередях будут отсортированы по value() своих аннотаций.
Так что вызываем последовательно методы из queue1, queue2 и queue3.
Помимо этого, исправил работу с Class, чтобы не использовалась его "сырая" форма, а также объект создаю посредством класса Constructor.