コンパイル時アノテーションプロセッサー
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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- アノテーションの定義:要素とデフォルト値
- 保持ポリシーと対象型
- 実行時のアノテーション処理
- コンパイル時アノテーションプロセッサー