Как использовать javax.tools.JavaCompiler для создания функции, которая вызывает список методов дочернего класса, отфильтрованных по пользовательской аннотации? - PullRequest
2 голосов
/ 03 апреля 2020

У меня такая необычная (я думаю?) Ситуация

public abstract class Base {

   public Base() {
       // code
   }

   public final void executeAll() {
      final Foo foo = new Foo();
      final Bar bar = new Bar();
      // now execute all method of "this" that: 
      //   - have annotation mark
      //   - have return type void
      //   - accept (foo, bar) has parameters
      //   - name can be whatever you want
      //   - protected
   }

   @Retention(RetentionPolicy.RUNTIME)
   @Target({ElementType.METHOD})
   protected @interface Mark{
   }
}

Теперь у меня есть класс, который расширяет Base и имеет несколько методов с сигнатурой, как описано в методе executeAll, например:

public class Test extends Base {

   @Mark
   protected void willBeCalled(Foo a, Bar b) {
   }

   @Mark
   protected void alsoThisOne(Foo a, Bar b) {
   }

   @Mark
   protected void yep(Foo a, Bar b) {
   }

}

Я знаю, что этого легко достичь, создав «защищенный абстрактный» Collection<BiConsumer<Foo, Bar>> getToBeCalled(), заставив каждого потомка расширить его и написать метод executeAll () следующим образом:

   protected abstract Collection<BiConsumer<Foo, Bar>> getToBeCalled();

   public final void executeAll() {
      final Foo foo = new Foo();
      final Bar bar = new Bar();
      getToBeCalled().stream.forEach(bic-> bic.accept(foo, bar));
   }

Но это это не , чего я хочу достичь. Мне нужен способ получить методы для выполнения из дочернего класса без какого-либо серьезного вмешательства со стороны разработчика (вот почему я подумал о аннотации, чтобы отметить метод, который нужно выполнить, и ничего более).

Прямо сейчас У меня есть работающая реализация, которая внутри Базового пустого конструктора сканирует все доступные методы с this.getClass().getMethods(), фильтрует их (должен иметь аннотацию Mark, принимать только параметр Foo и параметр Bar в этом порядке и возвращать void, быть защищенным) и сохранять их в private List<Method> methods;, позже использованном executeAll для вызова каждого метода.

Недавно я также прочитал это: https://www.optaplanner.org/blog/2018/01/09/JavaReflectionButMuchFaster.html ...

... и просто - for-fun реализовал версию MethodHandle (я думаю, что, возможно, в моем случае использования будет быстрее), и планирую сделать версию LambdaMetafactory ... но я действительно заинтригован решением javax.tools.JavaCompiler. Я все еще пытаюсь выяснить, как это сделать, хотя ... Я продолжаю свой поиск и фильтрацию названий методов, я сохраняю только имена ... и сейчас? Как я могу преобразовать список имен методов (к которому я знаю, что у меня есть доступ, так как я звоню из "this" и объявлен защищенным в дочернем классе, а также определен c сигнатура) для чего-то пригодного для использования, например, одного private final BiConsumer<Foo, Bar> callAll;, вычисленного и сохраненного конструктором Base () и вызванного функцией executeAll следующим образом:

public abstract class Base {

   private final BiConsumer<Foo, Bar> callAll;

   protected Base() {
       // get all methods <<< already done
       Method[] methods = ;
       // filter them by annotation, visibility and signature <<< already done
       List<Method> filtered> = ;
       // save only the names <<< already done
       List<String> names = ;
       // use javax.tools.JavaCompiler somehow <<< I miss this
       callAll = ???; 
   }

   public final void executeAll() {
      final Foo foo = new Foo();
      final Bar bar = new Bar();
      callAll.accept(foo, bar);
   }

   @Retention(RetentionPolicy.RUNTIME)
   @Target({ElementType.METHOD})
   protected @interface Mark{
   }
}

Конечно, идея состоит в том, чтобы использовать BiConsumer в качестве callAll - это просто идея, если есть что-то лучшее, я совершенно согласен с предложением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...