0Pricing
Java Academy · レッスン

コンパイル時アノテーションプロセッサー

AbstractProcessor を作成し、ソースファイルの生成やコンパイル時のコード検証を行います。

「コンパイル時アノテーションプロセッサー」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

アノテーションプロセッサとは

アノテーションプロセッサ(APT — Annotation Processing Tool)はコンパイル中に実行されます。ソースコードのアノテーションを調べ、新しいソースファイルやリソースファイルを生成したり、コンパイラのエラーや警告を発生させたりできます。

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 ではなく Element を扱います。ソースコードはまだコンパイルされていないためです。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 は、既存クラスの AST を変更する標準外の APT 拡張を使用します(仕様では許可されていません)。@Data、@Builder、@Getter などのアノテーションによって、メソッドをコンパイル済みクラスへ直接生成します。

MapStruct によるコード生成

MapStruct は、コンパイル時に型安全な mapper 実装を生成します。@Mapper が付いたインターフェースを読み取り、通常の Java クラスとして実装を書き出すため、実行時のリフレクションは不要です。

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

アノテーションプロセッサのテスト

プロセッサの単体テストには、google/compile-testing または Kotlin 用の Kapt を使用します。ソース文字列を入力し、生成されたファイルやコンパイラエラーを検証します。

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 を使用します。これにより、実行時のリフレクションによるオーバーヘッドをなくせます。

よくある質問

「コンパイル時アノテーションプロセッサー」レッスンは無料ですか?

はい。「コンパイル時アノテーションプロセッサー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「コンパイル時アノテーションプロセッサー」で何を学びますか?

AbstractProcessor を作成し、ソースファイルの生成やコンパイル時のコード検証を行います。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「コンパイル時アノテーションプロセッサー」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. アノテーションの定義:要素とデフォルト値
  2. 保持ポリシーと対象型
  3. 実行時のアノテーション処理
  4. コンパイル時アノテーションプロセッサー
← Java Academyに戻る