Lombok(ロンボク)は、JavaのGetter・Setter・コンストラクタ・equalsなどの定型コードを、アノテーションからコンパイル時に生成するライブラリです。9行の@Dataクラスは、生成後のコードに展開すると74行になります。この記事では、最新版1.18.48(2026年9月1日)を前提に、主要アノテーションの使い方と、Maven・Gradle・Spring Boot 4.1での設定を説明します。JDK 25〜27でコンパイルして確かめた、つまずきやすい点もあわせてまとめました。
まとめ:Lombokの要点
- 読み方は「ロンボク」。正式名称はProject Lombokで、コンパイル時に注釈処理でメソッドを生成します。実行時にlombok.jarは要りません。
- 最新版は1.18.48で、JDK 27に対応しています。JDK 27に1.18.46を組み合わせるとコンパイラが例外で止まるため、JDKを上げたらLombokも上げます。
- JDK 23以降は、Lombokをクラスパスに置いただけでは何も生成されません。Mavenでは注釈処理を明示的に有効にする必要があり、この記事では
annotationProcessorPathsを使います。GradleはcompileOnlyとannotationProcessorの2行を書きます。 @Dataは便利ですが、子クラスでは親のequalsを呼ばず、HashSetに入れた後にフィールドを変えると見つからなくなり、双方向の参照ではtoStringが再帰して落ちます。JPAエンティティには@Getterと@NoArgsConstructor(access = AccessLevel.PROTECTED)を使うのが安全です。- Lombokは非推奨ではありません。ただし不変のデータ入れ物はrecordで書けるので、新しく書くDTOはrecordを優先します。
Lombokとは:読み方とコンパイル時に生成する仕組み
Lombokの読み方は「ロンボク」です。インドネシアのロンボク島と同じ綴りのため、検索するときは「lombok java」と添えると技術情報に絞れます。配布元はProject Lombokの公式サイトで、ソースはGitHubのprojectlombok/lombokで公開されています。
Lombokは、javacの注釈処理(アノテーションプロセッサ)の段階でクラスの構文木に手を入れ、getterやコンストラクタを追加します。生成されたメソッドはソースには現れませんが、クラスファイルには普通のメソッドとして入ります。次の@DataクラスをLombok 1.18.48でコンパイルし、u.setName("Sato")のあとにgetName()とtoString()を表示する別のMainクラスを用意し、lombok.jarを外したクラスパスで実行すると、Sato User(id=1, name=Sato)と表示されました。実行時の依存にならないので、Mavenではprovided、GradleではcompileOnlyで足ります。
package demo;
import lombok.Data;
@Data
public class User {
private final Long id;
private String name;
}
この9行のファイルにjava -jar lombok.jar delombokをかけると、74行のJavaコードになります。コンストラクタ、getter 2本、setter 1本、equals・canEqual・hashCode・toStringが並び、それぞれに@lombok.Generatedが付きます。Lombokが減らしているのはこの65行ぶんの記述です。
Lombokの最新バージョンと対応JDK(1.18.48・JDK 27)
Lombokは新しいJDKが出るたびに対応版を出しています。直近の版と主な変更点は次のとおりです(公式の変更履歴より)。
| 版 | 公開日 | 主な変更 |
|---|---|---|
| 1.18.48 | 2026-09-01 | JDK 27対応・@SuperBuilderが正式版へ |
| 1.18.46 | 2026-04-22 | JDK 26対応 |
| 1.18.44 | 2026-03-11 | @JacksonizedがJackson 3に対応 |
| 1.18.42 | 2025-09-18 | @Log系でアクセス修飾子を指定可能に |
| 1.18.40 | 2025-09-04 | JDK 25対応 |
JDKに対応していない版を使うと、コンパイラごと止まります。同じ@Dataクラスで組み合わせを変えて試した結果が次の表です。
| JDK | Lombok | 結果 |
|---|---|---|
| 27 | 1.18.48 | 成功 |
| 27 | 1.18.46 | 失敗(ExceptionInInitializerError) |
| 26 | 1.18.46 | 成功 |
| 25 | 1.18.48 | 成功 |
| 25 | 1.18.20 | 失敗(ExceptionInInitializerError) |
JDK 27と1.18.46の組み合わせでは、原因としてClassNotFoundException: com.sun.tools.javac.tree.EndPosTableが出ます。JDK 25と1.18.20ではNoSuchFieldException: com.sun.tools.javac.code.TypeTag :: UNKNOWNです。どちらもLombokがjavacの内部クラスを参照していることが原因で、ソースを直しても解決しません。「An annotation processor threw an uncaught exception」と出たら、まずLombokの版を疑ってください。Java 25と27で変わった点はJava 21と25の違いとJava 27とは|非LTSの半年運用とG1・オブジェクトヘッダ既定化の影響にまとめています。
Spring Boot 4.1.2の依存管理(spring-boot-dependencies)が指定しているLombokも1.18.48です。Spring Bootの親POMを使っていれば、Bootを上げるとLombokも上がります(Spring Bootの依存バージョン一覧)。
Lombokの導入手順:Maven・Gradle・Spring Boot・IDE
導入は、ビルドツールへの依存追加と注釈処理の指定、IDEでの認識の2段階です。JDK 23から注釈処理の既定が変わったため、古い記事の手順では動かないことがあります。
MavenのannotationProcessorPaths設定とJDK 23以降の注釈処理の有効化
JDK 23では、javacがクラスパスから注釈処理を探して自動で動かす挙動が既定で無効になりました(JDK 23リリースノート、JDK-8321314)。Lombokをprovidedで足しただけのpom.xmlをJDK 25とmaven-compiler-plugin 3.15.0でビルドすると、@Dataが生成するはずのコンストラクタやsetterが見つからず、コンパイルエラーになりました。
[ERROR] .../Main.java:[5,18] クラス demo.Userのコンストラクタ Userは指定された型に適用できません。
アノテーションの読み込み自体は成功するので、エラーの出る場所はLombokを使う側のクラスになります。Lombok公式のMaven手順どおり、依存に加えてannotationProcessorPathsにもLombokを書くと通ります。
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.48</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.48</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
pom.xmlを書き換えずに、mvn compile -Dmaven.compiler.proc=fullで旧来の挙動に戻す方法もあり、こちらでも通りました。ただし、ほかの注釈処理までクラスパスから拾うようになるため、恒久対応にはannotationProcessorPathsを使います。
Gradleの依存設定(compileOnlyとannotationProcessor)
Gradleは注釈処理用の経路を最初から分けているので、JDK 23の変更の影響を受けません。compileOnlyとannotationProcessorの両方に同じ依存を書きます。compileOnlyだけだと、アノテーションは解決できてもメソッドが生成されません。テストコードでLombokを使う場合は、test付きの2行も足します。
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.48'
annotationProcessor 'org.projectlombok:lombok:1.18.48'
testCompileOnly 'org.projectlombok:lombok:1.18.48'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.48'
}
Spring Boot 4.1のInitializrが生成する設定
Spring InitializrでLombokを選ぶと、Spring Boot 4.1.2のpom.xmlには、依存が<optional>true</optional>で入ります。加えて、maven-compiler-pluginのdefault-compileとdefault-testCompileの両方に、バージョン無しのannotationProcessorPathsが生成されます。版は親POMの依存管理から解決され、このpom.xmlのままJDK 25でビルドできました。Gradle版の生成結果は、上の4行(版の指定なし)と同じ形です。Spring Bootのアノテーションと組み合わせる場面はSpring Bootのアノテーション一覧で扱っています。
IntelliJ IDEAとEclipseでの認識設定
IntelliJ IDEAは2020.3からLombokプラグインを同梱するようになりました(JetBrainsサポートの回答)。一方、Lombok公式のIntelliJ導入ページは、プラグインなしで動く範囲を2020.3〜2023.1と書き、それより新しい版ではプラグインの追加を案内しています。現行版では、Settings → Pluginsで「Lombok」が入っていて有効かを確認し、見当たらなければMarketplaceから入れてください。Marketplaceのプラグイン(ID 6317)は、2026.3系(ビルド263.x)向けの版まで更新されています。
Eclipseは、lombok.jarをインストーラーとして起動し、Eclipseのインストール先を指定して再起動します。Eclipse自体の導入はEclipseとは?使い方・導入・日本語化を最新版2026-09で解説を参照してください。
java -jar lombok.jar
Lombokの主要アノテーション一覧
よく使うアノテーションと、生成される内容を一覧にしました。最初は@Getter・@Setter・コンストラクタ系・@Builder・@Slf4jから始めれば足ります。
| アノテーション | 生成される内容 | 主な用途 |
|---|---|---|
| @Getter / @Setter | getter / setter | フィールドの公開 |
| @Getter(lazy=true) | 初回呼び出し時に1回だけ計算するgetter | 重い計算のキャッシュ |
| @ToString | toString() | ログ出力 |
| @EqualsAndHashCode | equals() / hashCode() | 比較・Mapのキー |
| @NoArgsConstructor | 引数なしコンストラクタ | JPA・JSONの復元 |
| @RequiredArgsConstructor | 未初期化のfinal・@NonNullを取る | コンストラクタ注入 |
| @AllArgsConstructor | 各フィールドを取る(static等を除く) | テストデータの作成 |
| @Data | @Getter等の5種を一括(後述) | 可変のデータクラス |
| @Value | final化したクラスとgetter等 | 不変の値オブジェクト |
| @Builder / @SuperBuilder | ビルダー | 引数の多い生成 |
| @With | 1項目だけ変えたコピーを返すメソッド | 不変オブジェクトの更新 |
| @NonNull | nullチェック | 引数の検査 |
| @Cleanup | close()の呼び出し | リソースの解放 |
| @SneakyThrows | 検査例外を宣言なしで送出 | throwsを足せない実装メソッド |
| @Slf4j / @Log4j2 / @Log | ロガーのフィールド | ログ出力 |
@CleanupはJava 7以降のtry-with-resourcesで、final付きのローカル変数を型推論するvalはJava 10以降のfinal varで、それぞれ言語機能として書けます。新しいコードでLombok版を選ぶ理由はほとんどありません。
主要アノテーションの使い方とコード例
この章のコードは要点だけを抜き出したもので、import文を省いています。実際にはlombok.Getterなどのimportと、クラスごとのファイル分割が必要です。OrderRepositoryなどアプリケーション側の型は、それぞれのプロジェクトで定義されているものとします。
@Getter・@SetterとAccessLevelによる公開範囲の指定
クラスに付けるとstatic以外の全フィールド、フィールドに付けるとそのフィールドだけが対象です。finalフィールドにはsetterを生成しません。AccessLevelを渡すと生成メソッドの公開範囲を変えられるので、読み取りは公開し、書き換えはクラス内に閉じる、といった指定ができます。
@Getter
public class Account {
@Setter(AccessLevel.PRIVATE)
private long balance;
private String owner;
}
@RequiredArgsConstructorと@NoArgsConstructor(access = AccessLevel.PROTECTED)
Springのコンストラクタ注入には@RequiredArgsConstructorが向いています。引数になるのは、宣言時に初期化していないfinalフィールドと、同じく未初期化の@NonNullフィールドです。JPAエンティティは引数なしコンストラクタを求めますが、アプリケーションのコードから空のオブジェクトを作られたくありません。そこで@NoArgsConstructor(access = AccessLevel.PROTECTED)を使います。生成されたコンストラクタの修飾子をリフレクションで確かめると、protectedになっていました。
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository repository;
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
public Member(String name) {
this.name = name;
}
}
エンティティの書き方とDTOとの役割分担はエンティティクラスとは?JPAとEF Coreの書き方・DTOとの違いを実行結果で解説で詳しく扱っています。
@Dataと@Valueの違い
@Dataは、@Getter・@Setter(final以外)・@ToString・@EqualsAndHashCode・@RequiredArgsConstructorをまとめて付ける可変クラス向けのアノテーションです。@Valueはフィールドをprivate finalにし、クラス自体もfinalにします。setterは作りません。ただし、配列や可変オブジェクトの参照先まで不変にするわけではありません。@Valueを付けたPointをリフレクションで調べると、クラスのfinal修飾が確認できました。
@Value
public class Point {
int x;
int y;
}
// new Point(1, 2).toString() は Point(x=1, y=2)
@Builderでのフィールド初期値と@Builder.Default
@Builderを付けるとUser.builder().name("Sato").build()の形で組み立てられます。気を付けたいのは、クラスに@Builderを付けたときの非finalフィールドの初期値で、ビルダー経由では無視されます(次の章で実測)。ビルダーの設計、@SuperBuilderやrecordとの組み合わせ、Spring Bootでの使い方はJavaのBuilderパターン実装|Lombok @Builder・record・Spring Bootでの使い方にまとめています。
@NonNullとBean Validationの@NotNullの違い
Lombokの@NonNullを引数に付けると、メソッドの先頭にnullチェックが入り、nullならNullPointerExceptionを投げます。Bean Validation(Jakarta Validation)の@NotNullは、付けただけでは何も起きず、バリデーターが検証したときに違反として扱われます。Springの@Validatedなどでメソッド検証を有効にしていれば、引数の制約違反は標準設定でConstraintViolationException(設定によりMethodValidationException)になり、メソッド本体は実行されません。入力値の検証は@NotNullとバリデーションの仕組みで、検証の仕組みが無い場所でもnullを入口で止めたいときは@NonNullで、と使い分けます。
public void rename(@NonNull String name) {
this.name = name;
}
@Slf4jによるロガーフィールドの生成
@Slf4jをクラスに付けると、private static final org.slf4j.Logger logが生成され、すぐlog.info(...)を呼べます。Log4j 2を直接使うなら@Log4j2、JDK標準のロガーなら@Logです。1.18.42からは、@Slf4j(access = AccessLevel.PROTECTED)のように公開範囲も変えられます。
@Slf4j
public class OrderService {
public void place() {
log.info("order placed");
}
}
@SneakyThrowsの適用範囲と検査例外の扱い
@SneakyThrowsは、throws宣言なしで検査例外を外へ投げます。呼び出し側のコンパイラは例外を知らないため、tryブロックにIOExceptionを投げると宣言した処理がなければ、catch (IOException e)と書くとコンパイルエラーになります。ラムダ式そのものには付けられないため、Runnable.runのようにthrowsを足せない実装メソッドに限って使い、業務ロジックでは例外を明示します。
実測で分かった@Dataと@Builderの落とし穴
Lombokの警告を読み飛ばすと、実行時に初めて気付く不具合になります。JDK 25とLombok 1.18.48で、よくある書き方を実際に動かした結果です。
| 書き方 | 結果 | 直し方 |
|---|---|---|
| @Builderのフィールドに初期値 | status=null, items=null | @Builder.Default |
| 継承した@Dataクラスでequals | idが違ってもtrue | callSuper = true |
| HashSetに入れた後にsetId | contains=false | キーを不変にする |
| 双方向参照の@Data同士 | StackOverflowError | 関連をexclude |
1つ目は、private String status = "NEW";のように初期値を書いても、builder().build()で作るとnullになる問題です。コンパイル時には「@Builder will ignore the initializing expression entirely」という警告が出ています。@Builder.Defaultを付けると、status=NEW、items=[]になりました。
2つ目は、親クラスが@Dataでidを比較するequalsを持ち、その子クラスにも@Dataを付けた場合です。子クラスに生成されるequalsは子クラスのフィールドしか比較せず、親のequalsも呼ばないため、idが1と2の2つのオブジェクトが等しいと判定されました。コンパイル時の警告「Generating equals/hashCode implementation but without a call to superclass」が出ているので、@EqualsAndHashCode(callSuper = true)を足すと親のequalsも呼ばれ、falseに戻ります。
3つ目は、@DataのhashCodeがstaticとtransient以外の全フィールドから計算されることが原因です。HashSetに入れた後でフィールドを変えると、同じオブジェクトなのにcontainsがfalseを返しました。4つ目は、toStringとhashCodeが関連先のオブジェクトの同じメソッドを呼ぶためで、部署と社員が互いを参照するクラスでは呼び出しが循環し、StackOverflowErrorで落ちました。
JPAのエンティティはまさにこの条件(idが後から入る、関連が双方向、遅延ロード)を満たすため、エンティティに@Dataは付けません。@Getterと@NoArgsConstructor(access = AccessLevel.PROTECTED)を基本にします。@ToStringはgetter経由でフィールドを読むので、まだ読み込まれていない遅延ロードの関連を含めると、出力した時点でSQLが走ります。セッションが閉じた後ならLazyInitializationExceptionになります。関連フィールドは@ToString.Excludeで外してください。equalsとhashCodeは、Hibernate ORM 7.1の公式ガイドが勧めるとおり、可変のフィールドやデータベースが採番するidを避け、変わらない業務上のキー(自然キー)で手書きします。@Dataは、DTOやフォームのように、ライフサイクルが短くて関連を持たないクラスに限るのが安全です。
lombok.configによるプロジェクト共通の設定
Lombokの挙動は、ソースのディレクトリに置くlombok.configで変えられます。ファイルは親ディレクトリへさかのぼって読まれるので、リポジトリのルートにconfig.stopBubbling = trueを書き、それより上の設定を読まないようにしておきます(公式の設定キー解説)。
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
lombok.anyConstructor.addConstructorProperties = true
lombok.accessors.chain = false
| キー | 効果 |
|---|---|
| config.stopBubbling | 親ディレクトリの設定を読まない |
| lombok.addLombokGeneratedAnnotation | @lombok.Generatedを付ける(既定true) |
| lombok.anyConstructor.addConstructorProperties | trueで@ConstructorPropertiesを付ける |
| lombok.accessors.chain | trueでsetterがthisを返す(既定false) |
@lombok.Generatedが付いたメソッドは、JaCoCoがレポート生成時のカバレッジの集計対象から外します。先ほどのdelombokの出力にも@lombok.Generatedが付いていました。使っている版が受け付けるキーの一覧は、java -jar lombok.jar config -gで出せます。
delombokによる生成コードの確認とLombok依存の除去
Lombokが何を生成したかを確かめたいとき、またはLombokを外したいときはdelombokを使います。次のコマンドは、src/main/javaのアノテーションを展開したソースをdelombokedへ書き出します。
java -jar lombok.jar delombok src/main/java -d delomboked
冒頭のUserクラスは、この処理で9行から74行になりました。ただし、既定の出力にはメソッドごとに@lombok.Generatedが残り(このクラスでは8か所)、Lombokを外してコンパイルすると「package lombok does not exist」で失敗します。依存を外す目的なら、展開する前にlombok.configへlombok.addLombokGeneratedAnnotation = falseを書きます。この設定で展開した66行のファイルは、Lombokなしでコンパイルできました。公式のdelombok解説はMaven用とsbt用のプラグインを、Gradleの導入ページはGradle用のプラグインを案内しています。
Lombokは非推奨か:recordとの使い分けと判断基準
Lombokが非推奨になった事実はありません。2026年9月に出た1.18.48でもJDK 27への対応が追加されています。「非推奨」と言われる理由は、主に次の2つです。
1つ目は、Java 16で正式化されたrecordです。public record PointR(int x, int y) {}の1行で、コンストラクタ・アクセサ・equals・hashCode・toStringが言語機能として揃います。外部ライブラリも注釈処理も要りません。@Value版と比べると、アクセサ名がgetX()ではなくx()、toStringがPointR[x=1, y=2]の形式になります。加えて、recordはほかのクラスを継承できず、コンポーネント以外のインスタンスフィールドも宣言できません(Oracleのrecord解説)。@Valueからrecordへ移すときは、この2点に引っかからないかを先に確認します。recordの詳細はJavaのレコードクラス(record)とは?で解説しています。
2つ目は、javacの内部APIに依存する作りです。JDK 25以降でLombok 1.18.48を使うと、コンパイルは成功するものの、sun.misc.Unsafe::objectFieldOffset has been called by lombok.permit.Permitという警告が毎回出ます。JEP 498は、こうしたメモリアクセス用メソッドを将来のJDKで例外にし、その後削除する計画を示しています。JDK 27(2026年9月15日GA)とLombok 1.18.48で試した範囲では、警告が出るだけでコンパイルは成功しました。とはいえ、JDKの新版が出るたびにLombokの対応版を待つ必要がある点は変わりません。
このため、判断基準は次のとおりです。
- 新しく書く不変のDTO・値オブジェクト:recordを使います。Lombokを入れる理由になりません。
- JPAエンティティ:Jakarta Persistence 3.2の仕様が「enum・record・interfaceはエンティティに指定できない」と定めています。Lombokの
@Getterと@NoArgsConstructorを使います。 - ビルダー・ロガー・コンストラクタ注入:record単体では代わりにならないので、Lombokが手間を減らします。
- JDKを毎回すぐ上げるプロジェクト:Lombokの対応版を待つ期間を見込みます。JDK 27では1.18.48がGA(2026年9月15日)より前に出ましたが、JDK 26ではGA(2026年3月17日)から1.18.46まで36日かかりました。
既存のSpring Bootシステムで、エンティティとDTOの整理やJavaのバージョンアップをまとめて進めたい場合は、フルスクラッチ開発の支援もご相談いただけます。ORMの選定から見直すならJava ORM(O/Rマッパー)の種類と選び方が参考になります。
よくある質問
Lombokの読み方は?
「ロンボク」と読みます。正式名称はProject Lombokです。インドネシアのロンボク島と同じ綴りなので、検索では「lombok java」のように添えると技術情報が出やすくなります。
Lombokの最新バージョンは?Java 25やJava 27で使えますか?
2026年10月時点の最新版は1.18.48(2026年9月1日公開)です。JDK 25は1.18.40、JDK 26は1.18.46、JDK 27は1.18.48で対応しました。JDK 27に1.18.46を組み合わせると、コンパイラが例外で止まります。
Mavenで「シンボルが見つかりません」になるのはなぜですか?
JDK 23以降は、クラスパスにLombokを置いただけでは注釈処理が動かないためです。maven-compiler-pluginのannotationProcessorPathsにLombokを追加してください。GradleならannotationProcessorの行が抜けていないかを確認します。
Lombokは非推奨なのですか?
非推奨ではなく、1.18.48でもJDK 27への対応が続いています。不変のデータクラスはrecordで書けるため、この記事ではLombokをエンティティ・ビルダー・ロガーなどに絞って使うことをすすめます。
@NoArgsConstructor(access = AccessLevel.PRIVATE)は何に使いますか?
引数なしコンストラクタを外から呼べなくしたいときに使います。staticメソッドだけを持つユーティリティクラスならPRIVATEにします。JPAエンティティでは、PRIVATEではなくPROTECTEDを指定してください。