Java Academy · Урок

Процессоры аннотаций во время компиляции

Пишите AbstractProcessor для создания исходных файлов или проверки кода во время компиляции.

Урок 4 из 413 шагов

«Процессоры аннотаций во время компиляции» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

Что такое процессоры аннотаций

Процессоры аннотаций (APT — инструмент обработки аннотаций) запускаются во время компиляции. Они анализируют аннотации исходного кода и могут создавать новые исходные файлы, файлы ресурсов или выдавать ошибки и предупреждения компилятора.

AbstractProcessor: базовый класс

Расширьте javax.annotation.processing.AbstractProcessor. Переопределите process(), чтобы обрабатывать аннотированные элементы. Объявите поддерживаемые аннотации и версию исходного кода Java.

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;

@SupportedAnnotationTypes("com.example.GenerateBuilder")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class BuilderProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations,
                           RoundEnvironment roundEnv) {
        for (Element e : roundEnv.getElementsAnnotatedWith(GenerateBuilder.class)) {
            generateBuilder((TypeElement) e);
        }
        return true;
    }
    private void generateBuilder(TypeElement cls) { /* generate source */ }
}

Регистрация процессора

Зарегистрируйте процессор в META-INF/services/javax.annotation.processing.Processor, указав полное имя класса. Инструменты сборки (Maven, Gradle) автоматически обнаружат его.

# META-INF/services/javax.annotation.processing.Processor
com.example.BuilderProcessor

Создание исходных файлов

Используйте processingEnv.getFiler().createSourceFile(), чтобы записать новый файл .java. Затем компилятор скомпилирует созданный файл в том же или следующем раунде.

JavaFileObject file = processingEnv.getFiler()
    .createSourceFile("com.example.UserBuilder");
try (Writer w = file.openWriter()) {
    w.write("package com.example;\n");
    w.write("public class UserBuilder {\n");
    w.write("  // generated builder\n");
    w.write("}\n");
}

Изучение модели элементов

Процессоры аннотаций работают с элементами Element, а не с классами Class: исходный код ещё не скомпилирован. Используйте TypeElement, VariableElement и ExecutableElement.

TypeElement classElement = (TypeElement) element;
String className = classElement.getSimpleName().toString();
List<VariableElement> fields = classElement.getEnclosedElements().stream()
    .filter(e -> e.getKind() == ElementKind.FIELD)
    .map(e -> (VariableElement) e)
    .collect(Collectors.toList());

Выдача ошибок компилятора

Вызовите processingEnv.getMessager().printMessage(), чтобы выдать ошибку, предупреждение или примечание. Так пользовательские аннотации ограничений сообщают о нарушениях во время компиляции.

processingEnv.getMessager().printMessage(
    Diagnostic.Kind.ERROR,
    "@GenerateBuilder requires at least one field",
    element
);

Многораундовая обработка

Обработка аннотаций происходит по раундам. Если вы создаёте файл, содержащий аннотации, процессор может снова запуститься в следующем раунде. roundEnv.processingOver() сообщает о последнем раунде.

if (roundEnv.processingOver()) {
    // last round — write summary files or do cleanup
}

Как работает Lombok

Lombok использует нестандартное расширение APT, которое изменяет AST существующих классов (что не разрешено спецификацией). Его аннотации, такие как @Data, @Builder и @Getter, напрямую добавляют методы в скомпилированный класс.

Генерация кода MapStruct

MapStruct создаёт типобезопасные реализации преобразователей во время компиляции. Он читает интерфейсы с аннотацией @Mapper и записывает реализации как обычные классы Java, не используя рефлексию во время выполнения.

@Mapper
public interface UserMapper {
    UserDto toDto(User user);
    User toEntity(UserDto dto);
}
// MapStruct generates: UserMapperImpl.java at compile time

Тестирование процессоров аннотаций

Используйте google/compile-testing или Kapt (для Kotlin), чтобы писать модульные тесты процессоров. Передавайте строки исходного кода и проверяйте созданные файлы или ошибки компилятора.

JavaFileObject src = JavaFileObjects.forSourceString("Test",
    "@GenerateBuilder public class Test { private String name; }");
Compilation c = Compiler.javac().withProcessors(new BuilderProcessor()).compile(src);
CompilationSubject.assertThat(c).succeeded();
CompilationSubject.assertThat(c).generatedSourceFile("TestBuilder");

Упаковка процессора

Поместите процессор в отдельный модуль Maven. Модуль аннотаций, содержащий только аннотации, является зависимостью compile; модуль процессора использует область annotationProcessor и никогда не является зависимостью времени выполнения.

// build.gradle:
dependencies {
    implementation "com.example:my-annotations:1.0"
    annotationProcessor "com.example:my-processor:1.0"
}

Быстрая проверка

Где регистрируют процессор аннотаций для автоматического обнаружения?

Итоги

Расширьте AbstractProcessor, зарегистрируйте процессор в META-INF/services, создавайте исходный код с помощью Filer и выдавайте ошибки с помощью Messager. Упаковывайте процессоры отдельно. Используйте compile-testing для модульных тестов. Это устраняет накладные расходы рефлексии во время выполнения.

Можно начать бесплатно

Изучай Java с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
104
Уроки
374

Часто задаваемые вопросы

Урок «Процессоры аннотаций во время компиляции» бесплатный?

Да — полный текст урока «Процессоры аннотаций во время компиляции» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «Процессоры аннотаций во время компиляции»?

Пишите AbstractProcessor для создания исходных файлов или проверки кода во время компиляции. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Процессоры аннотаций во время компиляции»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Определение аннотаций: элементы и значения по умолчанию
  2. Политики хранения и типы целей
  3. Обработка аннотаций во время выполнения
  4. Процессоры аннотаций во время компиляции
← Назад к Java Academy