Как вы используете обработку аннотаций Java 1.6 для совмещения времени компиляции?

Я создал аннотацию, применил ее к DTO и написал обработчик аннотаций в стиле Java 1.6. Я вижу, как заставить annotationProcessor записать новый исходный файл, а это не то, что я хочу делать, я не вижу или не могу узнать, как заставить его изменить существующий класс (в идеале просто изменить байтовый код). Модификация на самом деле довольно тривиальна, все, что я хочу, чтобы процессор сделал, это вставить новый метод получения и установки, имя которого происходит от значения обрабатываемой аннотации.

Мой обработчик аннотаций выглядит так:

@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes({ "com.kn.salog.annotation.AggregateField" })
public class SalogDTOAnnotationProcessor extends AbstractProcessor {

    @Override
    public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
        //do some stuff
    }
}

person Steve    schedule 28.04.2010    source источник


Ответы (4)


Вы ищете «Инструментарий», что и делают фреймворки вроде AspectJ. В этом случае вы должны указать банку в командной строке с параметром «-agent», а затем иметь возможность фильтровать все загруженные классы. На этом этапе фильтрации вы можете проверить аннотации и изменить байт-код до его загрузки в виртуальную машину. Библиотеки для выполнения фактической модификации байт-кода включают «asm» и, возможно, оболочки высокого уровня «cglib» и «javassist». Вы даже можете предварительно скомпилировать свои классы, чтобы сгенерировать список классов, которые должны быть инструментированы вами, чтобы сделать фильтрацию вначале немного быстрее.

См. Java.lang.instrumentation для получения дополнительной информации.

person Daniel    schedule 04.05.2010

По своей конструкции средство обработки аннотаций не позволяет напрямую изменять обрабатываемый исходный код. Однако можно сгенерировать подклассы обрабатываемого типа или суперкласс обрабатываемого типа. При некотором планировании это позволяет частично изменить рассматриваемый тип. Я написал пример того, как это может сочетаться; см. эту запись в блоге для более подробного объяснения и некоторый образец кода.

person Joe Darcy    schedule 29.04.2010

Вы должны использовать внутренние классы компилятора - немного вдохновения:

Но это балансирование на грани. Ваша программа будет компилироваться только на Sun / OpenJDK, и в будущих версиях могут возникнуть проблемы (внутренний API может измениться). Хотя после компиляции это стандартный байт-код, он будет работать везде.

Кстати: если вы хотите использовать его в Eclipse, вы должны добавить для него специальную поддержку, потому что Eclipse использует нестандартный компилятор. Ваш дизайн должен быть более сложным, и вы должны добавить уровень абстракции к вашему процессору, как это делает Lombok.

person Franta    schedule 05.04.2012
comment
Это прекрасные примеры. Спасибо! - person Daniel Sperry; 29.01.2014

Для этого вам нужно расширить компилятор javac, а это значит, что сборка вашей программы не будет такой переносимой, как обычное приложение. См. http://weblogs.java.net/blog/cayhorstmann/archive/2006/06/say_no_to_prope.html для получения дополнительной информации о том, как кому-то удалось этого добиться.

person Xr.    schedule 28.04.2010
comment
Это определенно решение, но я почти уверен, что это не единственное решение. То, что я хочу сделать, можно сделать с помощью нескольких существующих фреймворков / наборов инструментов, например javassist. Я пытался избежать введения зависимости, которая, по-видимому, не является строго необходимой, однако введение обработки аннотаций в JDK1.6 выглядело так, как будто функциональность javassist запекалась. Возможно, я был неправ, но мне все еще нужен третий party инструмент для выполнения ткачества времени компиляции. - person Steve; 28.04.2010