Добавление кода в класс Java w/Instrumentation: ASM или BCEL?

Я пишу игровой движок/библиотеку, в которой у меня есть класс диспетчера событий, который отправляет события, вызывая методы прослушивания "зарегистрированных" классов обработчиков событий. Можно зарегистрировать обработчик/прослушиватель событий с диспетчером событий, вызвав соответствующий метод диспетчера.

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

Я понимаю, что для использования Instrumentation следует использовать API-интерфейс байтового кода. Я знаю два - ASM и BCEL. Какой из них я должен использовать? Очевидно, это несколько простая задача, которую я пытаюсь сделать, поэтому я хочу тот, который легче изучить и лучше документировать.

EDIT: Вот пример.

Класс обработчика исходных событий:

@Handler //indicates this this class should be transformed
public class MouseEventHandler implements EventHandler<MouseEvent>
{
    //hidden default constructor
    public void handleEvent(MouseEvent event)
    { ... }
}

После преобразования:

@Handler
public class MouseEventHandler implements EventHandler<MouseEvent>
{
    public MouseEventHandler()
    {
        //add this line of code to default constructor
        Game.getEventDispatcher().addEventHandler(this);
    }
    public void handleEvent(MouseEvent event)
    { ... }
}

Ответ 1

Я бы рассмотрел другие варианты, прежде чем переходить на байт-код манипуляции.

Ответ 2

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

Тем не менее,

Game.registerHandler( this );

будет более объектно-ориентированным.

Альтернативой добавлению логики в каждый класс является представление factory, который отвечает за создание экземпляров обработчиков.

HandlerFactory.createMouseHandler();

И метод createMouseHandler содержит что-то вроде

Handler mh = new MousheHandler();
registerHandler(mh);
return mh;

Если вы не хотите ни одного из этих параметров, я бы рассмотрел либо структуру фрейма (возможно, AspectJ), либо контейнер для инверсии управления (возможно, Spring IoC). Аспекты позволяют вам комментировать ваш источник и "переплетать" код в выбранных местах. Контейнер IoC позволяет вам контролировать жизненный цикл объекта (например, экземпляр). Оба используют инструментарий байт-кода за сценой.

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

ASM является низкоуровневым и работает на уровне java-байт-кода. Вы должны быть знакомы с этим. Структура очень хорошо разработана, руководство отлично, и это отличная библиотека. Одна из сторон может усложнить замену шаблонов байт-кода, поскольку для этого требуется так называемое преобразование "stateful". С другой стороны, вы полностью контролируете байт-код.

Javassist более высокий уровень. Вы не работаете на необработанном уровне байт-кода, немного более высоком уровне, например. поля читать/писать, отправлять сообщения, конструкторы. Кроме того, он позволяет указывать изменения с использованием регулярного синтаксиса java, который затем компилируется каркасом. API немного запутан, потому что проект рос с годами. Существует документация о структуре, но не так хорошо централизована, как с ASM.