@Getter を付けたフィールドの getter が、コンパイルの時点で存在しないものとして扱われます。
[INFO] --- compiler:3.13.0:compile (default-compile) @ demo ---
[INFO] Compiling 1 source file with javac [debug release 21] to target/classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] src/main/java/dev/errfix/App.java:[10,33] cannot find symbol
symbol: method getMessage()
location: class dev.errfix.App
[INFO] 1 error
エラー本文に lombok の語は 1 度も現れません。javac が報告しているのは「そのメソッドは無い」ということだけです。
件数は注釈を付けたフィールドの数ではなく、生成されるはずのメソッドを呼んでいる箇所の数になります
(@Getter を 2 つ持つクラスを 3 行で 4 回呼ぶソースなら 4 errors)。数十件が一度に並ぶのはこのため。
同じ原因が、ツールによって次のように見えます。
- javac 直接:
error: cannot find symbolと、その下にsymbol: method getMessage() - Maven:
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project ...: Compilation failure - 注釈処理を戻したあとに出る 2 段目:
Fatal error compiling: java.lang.ExceptionInInitializerError: com.sun.tools.javac.code.TypeTag :: UNKNOWN
直し方(Maven)
pom.xml の <properties> に <maven.compiler.proc>full</maven.compiler.proc> の 1 行を足します。
Lombok の依存宣言もソースコードも変えません(<maven.compiler.release> は元からある行です)。
<properties>
<maven.compiler.release>21</maven.compiler.release>
<maven.compiler.proc>full</maven.compiler.proc> <!-- この 1 行を足す -->
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.46</version>
<scope>provided</scope>
</dependency>
</dependencies>
この 1 行が読まれるのは maven-compiler-plugin 3.13.0 以降です。それより古いプラグインは full という値を知らず、
警告も出さずに無視します(3.12.1 で実測。ビルドログを proc で grep しても 1 行も引っかからないまま
cannot find symbol が残る)。自分のビルドが使っているプラグイン版は、ログの
--- compiler:3.13.0:compile (default-compile) --- の行に出ています。ここが 3.13.0 より小さければ、
プラグインの版も固定します。<build> ごと無ければ次をそのまま足し、maven-compiler-plugin の宣言が既にあるなら
<version> の行だけを足します。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
</plugin>
</plugins>
</build>
プラグイン版を書いていないプロジェクトでは、Maven 本体が既定を決めます。Maven 3.9.12 がバインドするのは 3.13.0、 Maven 3.8.8 は 3.1(どちらも実測)。JDK を上げるついでに Maven も上げていれば前者、ビルドサーバの Maven が 据え置きなら後者になります。
直し方(プロセッサのパスを明示する)
maven.compiler.proc を使わず、Lombok を注釈プロセッサとして名指しする書き方でも通ります。
足すのは下の <build> だけで、<properties> と <dependencies> は元のままです
(maven.compiler.proc は書きません)。
<properties>
<maven.compiler.release>21</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.46</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.46</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<annotationProcessorPaths> はプロセッサを探すパスを決めるだけで、コンパイル時のクラスパスとは別物です。
<dependencies> のほうを消して <annotationProcessorPaths> だけにすると、今度は import lombok.Getter; の行が
package lombok does not exist になります。両方に同じ座標を書くのが正しい形。
こちらは maven.compiler.proc を書かなくても注釈処理が走ります。理由は次の節にあります。
プロセッサを複数使うプロジェクト(Lombok と MapStruct の併用など)では、何を走らせるかがこの 1 箇所に集まります。
Lombok だけなら、前者の 1 行のほうが差分は小さい。
なぜ JDK 23 で出るのか
JDK 22 までの javac は、クラスパスを探して見つけた注釈プロセッサを、何の指定も無いまま実行していました。
Lombok を依存に足すだけで @Getter が展開されていたのは、この既定動作に乗っていたからです。
JDK 23 でその既定が変わり、注釈処理は明示的に要求されたときだけ走るようになりました。要求の仕方は javac の オプションで、次のどれか 1 つがあれば足ります。
-processor… プロセッサをクラス名で指定する--processor-path/--processor-module-path… プロセッサを探すパスを指定する-proc:only/-proc:full… 注釈処理を明示的に有効にする
Maven の maven.compiler.proc は -proc:full に、<annotationProcessorPaths> は --processor-path に対応します。
どれも渡していないビルドでは、プロセッサはクラスパスに置かれたまま起動しません。Lombok が動いていないので
getter は生成されず、それを呼んでいる行が cannot find symbol になる——エラーが指しているのは呼び出し側で、
実際に止まっているのは 1 段手前の注釈処理です。
これは API の削除でも非推奨でもなく、既定値の変更です。JDK 21 と 22 は同じソースをコンパイルして成功させながら、 変更を予告する注意書きを出していました。
Note: Annotation processing is enabled because one or more processors were found
on the class path. A future release of javac may disable annotation processing
unless at least one processor is specified by name (-processor), or a search
path is specified (--processor-path, --processor-module-path), or annotation
processing is enabled explicitly (-proc:only, -proc:full).
Use -Xlint:-options to suppress this message.
Use -proc:none to disable annotation processing.
境界は JDK 22 と 23 のあいだにあります。開発機を 21 に据え置いたままビルドサーバだけ 23 以降へ上げた構成では、 落ちるのは片側だけになります。
Lombok の版はどこに効くか
依存の版を上げるのは、この症状に対しては空振りになります。Maven Central の現行である 1.18.46 に上げても、
注釈処理を有効にしない限り cannot find symbol は 1 件も減りません(JDK 25 で実測)。プロセッサが起動していない
状態は、プロセッサの中身と関係が無いからです。
版が問われるのは、注釈処理を戻したあとです。-proc:full が渡ると javac は Lombok を起動し、そこで初めて
Lombok 側が JDK に追いついているかどうかが表に出ます。追いついていない組み合わせでは、Maven のログが
1 行だけこう変わります。
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project demo: Fatal error compiling: java.lang.ExceptionInInitializerError: com.sun.tools.javac.code.TypeTag :: UNKNOWN
javac を直接叩くと、同じ失敗がプロセッサ側の例外として出ます。
An annotation processor threw an uncaught exception.
Consult the following stack trace for details.
java.lang.ExceptionInInitializerError
at lombok.javac.apt.LombokProcessor.placePostCompileAndDontMakeForceRoundDummiesHook(LombokProcessor.java:174)
at lombok.javac.apt.LombokProcessor.init(LombokProcessor.java:96)
at lombok.core.AnnotationProcessor$JavacDescriptor.want(AnnotationProcessor.java:160)
-proc:full を付けて同じソースをコンパイルしたときの終了コードです。
| Lombok | JDK 23 | JDK 24 | JDK 25 |
|---|---|---|---|
| 1.18.30 | 0 | 3 | 3 |
| 1.18.32 | 0 | 3 | 3 |
| 1.18.34 | 0 | 3 | 3 |
| 1.18.36 | 0 | 3 | 3 |
| 1.18.38 | 0 | 0 | 0 |
| 1.18.46 | 0 | 0 | 0 |
注釈処理が止まるのは JDK 23 から、Lombok 自身が落ちるのは 24 から——層ごとに境界の版が違います。
JDK 23 へ上げただけなら、maven.compiler.proc を足せばここで測った範囲のどの Lombok でも通ります。24 以降へ
上げるなら 1.18.38 が下限で、Maven Central の版一覧に 1.18.36 と 1.18.38 の中間の版はありません。表に無い版は
測っていないので、ここから外挿はできません。
この上げには、コンパイルとは別の副作用が付いてきます。 1.18.38 へ上げる経路は必ず 1.18.34 を通過し、
その版から Lombok は生成メンバへ lombok.@Generated を既定で付けます。JaCoCo はその注釈が付いたメンバを
集計から外すので、コンパイルが通ったあと、カバレッジの母数だけが黙って縮みます(率は上がるため、閾値の
チェックも止まりません)。カバレッジを測っているプロジェクトなら、
Lombok を上げると JaCoCo のカバレッジ母数が縮む
を続けて読んでください。
JDK 24 以降では、注釈処理が成功したビルドにも sun.misc.Unsafe の警告が付いてきます。javac を直接叩いた場合は
Lombok が名指しされ、終了コードは 0 のまま。
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by lombok.permit.Permit
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
Maven 経由のビルドにも同じ 3 行が出ますが、そちらが名指しするのは Maven 自身が同梱している guava です
(com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper (file:/usr/share/maven/lib/guava.jar))。
どちらも BUILD SUCCESS に付随する警告で、cannot find symbol とも ExceptionInInitializerError とも別のもの。
切り分け
- Gradle でビルドしている:同じ
cannot find symbolが出ますが、境界は JDK の版ではありません。Gradle は 注釈プロセッサをannotationProcessor構成から取るため、Lombok をcompileOnlyにしか宣言していないビルドは JDK 21 でも同じエラーになります(Gradle 9.6.1 で JDK 21 と 25 の両方を実測)。同じ座標をannotationProcessorにも宣言すると、-proc相当の設定なしで通りました。 - Lombok 以外のコード生成も同時に消えている(MapStruct の実装クラス、Dagger のコンポーネントなど): JDK 23 が変えたのは「クラスパスの探索だけに頼っていた注釈処理」全体の扱いで、Lombok 固有の変更ではありません。 上の 3 種類のオプションはプロセッサの種類を問わないので、直し方も共通です(本記事が実測したのは Lombok だけ)。
cannot find symbolの直前にpackage ... does not existが出ている:生成メソッドではなく型そのものが 見つかっていない状態で、原因は別です。Jackson 2 → 3 の名前空間移行なら package com.fasterxml.jackson.databind does not exist の直し方、javax.*→jakarta.*なら package javax.persistence does not exist の直し方 が同じ形のエラーを扱っています。- コンパイルは直ったが、今度はカバレッジの数字が変わった:層 2 で Lombok を上げた場合の副作用です。 ビルドは成功したまま JaCoCo の母数だけが減ります(率は上がる)。 Lombok を上げると JaCoCo のカバレッジ母数が縮む を参照してください。
- IDE のビルドでは通る:IDE は自前のコンパイラ設定と Lombok 連携を持つことがあり、
mvnやjavacとは 別の経路で動きます。本記事が扱っているのはコマンドラインのビルド側で、IDE 側は検証していません。 CI だけが赤い場合は、まず CI のログで JDK 版とプラグイン版の 2 行を確認します。
検証環境
- image:
eclipse-temurin(digest 固定sha256:68868d04...= Temurin 25.0.3+9)。Maven 3.9.12、 maven-compiler-plugin 3.13.0(Maven が既定でバインドした版) - 再現:Lombok 1.18.38 を
providedで宣言したpom.xml(maven.compiler.procなし)でmvn clean compile→cannot find symbol・終了コード 1 - 修正:ソースも Lombok の版も変えず、
<maven.compiler.proc>full</maven.compiler.proc>の 1 行だけを足して 同じコマンド → 終了コード 0 - reproduce と fix の差は
pom.xmlの 1 行だけ。JDK・Lombok・App.javaは同一 - JDK 21 / 22 / 23 / 24 / 25 の比較は、各版の
eclipse-temurinイメージで同じApp.javaをjavacに かけて採取した。JDK 21 と 22 の注意書きも、その出力そのまま - Lombok の版マトリクスは、同じ
javac -proc:fullを Lombok 1.18.30 / 1.18.32 / 1.18.34 / 1.18.36 / 1.18.38 / 1.18.46 に対して回した終了コード - maven-compiler-plugin は 3.11.0 / 3.12.1 / 3.13.0 / 3.14.1 / 3.15.0 を
pom.xmlで固定して比較。 Maven 本体の既定バインドは 3.9.12 と 3.8.8 で確認 --processor-path単独、および-processorによるクラス名指定でも、-procを渡さずに JDK 25 で コンパイルが通ることを確認している(<annotationProcessorPaths>が対応する経路)<annotationProcessorPaths>だけを書いて<dependencies>から Lombok を外した形も試し、package lombok does not existになることを確認した- Gradle の 2 点は
gradle:9-jdk21とgradle:9-jdk25(Gradle 9.6.1)で採取 - 本文がコピペ用に指しているのは Maven Central の現行(Lombok 1.18.46、maven-compiler-plugin 3.15.0)。 ハーネスが検証した 1.18.38 / 3.13.0 は、境界を示す点として本文に別に置いている
- 引用したログは実際の出力そのままだが、絶対パス(検証用の作業ディレクトリ)とモジュール名だけは
src/main/java/...とdemoに短縮している
再現から修正までは errfix の検証ハーネスが機械的に確認しています。JDK 23 の既定変更と、注釈処理を要求する
オプションの一覧は、JDK 23 のリリースノート「Annotation processing in javac disabled by default」
(JDK-8321314)で確認しました。JDK 21 と 22 が予告の注意書きを出すこと、-proc:full で旧挙動に戻せることも
同じ項に書かれています。OpenJDK の Quality Outreach による告知「JDK 23: Changes Default Annotation Processing
Policy」は同じ内容の事前アナウンスです。maven.compiler.proc の値と既定は maven-compiler-plugin の compile
ゴールのドキュメントによります。