Error [package javax.persistence does not exist]

package javax.persistence does not exist の直し方(Spring Boot 3 で javax.persistence が消える)

FIX SUMMARY verified
Applies when
eclipse-temurin:17-jdkspring-boot-starter-data-jpa (Spring Boot 3 carries the Jakarta EE 9 namespace, so javax.persistence is absent from the compile classpath; Spring itself did not rename it)upgrading Spring Boot 2.x to 3.x with entity imports still on javax.persistence — the version bump, not any Spring setting, changes which namespace is on the classpath

Verified: reproduced in eclipse-temurin:17-jdk, then the package javax.persistence does not exist signature was gone after the fix (exit 0).

Spring Boot 2 系で動いていたアプリを 3 系に上げると、エンティティのコンパイルが次のエラーで止まります。

[ERROR] /app/src/main/java/App.java:[1,20] package javax.persistence does not exist

Spring の設定は変えていません。バージョンを上げただけです。javax 配下の別の API を import していれば、 その package 名で同じ形のエラーになります(下の対応表)。

直し方の要点を先に

import を jakarta.persistence.* に書き換えます。

// 旧:Spring Boot 2 系が運んでいたのは javax.persistence
// import javax.persistence.Entity;

// 新:Spring Boot 3 系が運ぶのは jakarta.persistence
import jakarta.persistence.Entity;

@Entity@Id@ColumnEntityManager など、javax.persistence 配下はすべて jakarta.persistence 配下へ動きます。

なぜ Spring Boot 3 で出るのか:依存セットが Jakarta 世代へ切り替わる

名前空間を javax.* から jakarta.* へ改名したのは Jakarta EE 9 です。Spring Boot 3 は、その世代の API を 管理する依存セットへ切り替わります。境界は Spring の設定ではなく、classpath にどちらの世代の API が居るかにあります。

同じ import javax.persistence.Entity;@Entity だけのソースを、依存だけ変えてコンパイルした実測です。

依存結果
Spring Boot 2.7.18spring-boot-starter-data-jpa成功(終了コード 0)
Spring Boot 3.2.12spring-boot-starter-data-jpapackage javax.persistence does not exist(終了コード 1)
Spring Boot 3.2.12javax.persistence:javax.persistence-api:2.2成功(終了コード 0)

3行目が、このエラーの性質を示しています。 Spring Boot 3.2.12 のまま、古い javax.persistence の API を classpath に足すと、コンパイルは通ります。つまりコンパイルを止めていた直接の原因は、Spring Boot 3 が 持ち込む設定や仕様ではなく、classpath に javax.persistence が無いことです。

この実測が言えるのはそこまでです。古い API を足せば Spring Boot 3 のアプリ全体が動く、という意味ではありません (Spring Data JPA 側は jakarta.persistence のエンティティを前提に組まれています)。3行目は診断のための実験であって、 直し方ではありません。直し方は、上に書いたとおり import を jakarta.persistence へ進めることです。

この境界は、次の2つの探し方を空振りさせます。

  • Spring の版を戻しても、根本は解決していない。 2.7 系に戻せばコンパイルは通りますが、それは Jakarta EE 8 世代へ 戻しただけです。Spring Boot 2.x のオープンソースサポートは 2.7.18 で終了しており(商用サポートは別途提供されています)、 いずれ同じ移行に当たります。
  • Spring の設定ファイルを探しても見つからない。 application.yml にも @Configuration にも、この境界を動かす 設定はありません。動かせるのは classpath にどちらの世代の API を置くかだけです。

消えたのは persistence だけではありません

同じ Jakarta EE 9 の改名で、Spring Boot 3 が運ぶ API はまとめて jakarta.* へ動きます。

Spring Boot 2 系Spring Boot 3 系
javax.persistence.*jakarta.persistence.*
javax.servlet.*jakarta.servlet.*
javax.validation.*jakarta.validation.*
javax.annotation.*@PostConstruct など)jakarta.annotation.*

実測したのは javax.persistence の境界です。ほかの package が動くこと自体は Jakarta EE 9 の名前空間変更に沿っています。

切り分け(うまくいかないとき)

  • import を全部直したのに、実行時に NoClassDefFoundError: javax/servlet/... が出る:自分のコードではなく、 依存しているライブラリが古い名前空間を要求しています。コンパイルが通っているのがその印です。 NoClassDefFoundError: javax/servlet/Filter の直し方 を参照してください。
  • package javax.mail does not exist が出ている:依存ので名前空間が変わる別の罠があります (Maven 座標が先に jakarta へ改名されている)。 package javax.mail does not exist の直し方 を参照してください。
  • 実行時に NoClassDefFoundError: javax/xml/bind/JAXBException が出る:それは Jakarta EE の改名ではなく、 JDK が JAXB の同梱をやめた話です(Java 11 / JEP 320)。直し方は依存を足すことで、import の書き換えではありません。 NoClassDefFoundError: javax/xml/bind/JAXBException の直し方 を参照してください。
  • エンティティは直したのに @PostConstruct などで止まるjavax.annotationjakarta.annotation へ動いています。 上の表で残りを確認します。
  • 依存ライブラリが Jakarta 世代に対応していない:自分のコードを直しても、そのライブラリが javax.* を要求する限り 解決しません。ライブラリ側の Jakarta 対応版を探すことになります。

検証環境

  • eclipse-temurin:17-jdk の中で Maven を実行(依存の取得にのみネットワークを使用)
  • 再現:import javax.persistence.Entity;@Entity のみのクラスを Spring Boot 3.2.12 の spring-boot-starter-data-jpa でコンパイルすると、package javax.persistence does not exist で終了コード 1
  • 修正:import を jakarta.persistence.Entity に変更すると、同じ Spring Boot 3.2.12 のまま終了コード 0・シグネチャ消滅

再現から修正までは errfix の検証ハーネスが機械的に確認しています。reproduce と fix の差は import 文の1行だけです。 「Spring Boot 2.7.18 では通り、3.2.12 で落ち、3.2.12 に古い javax.persistence-api を足すと通る」の3点は、 同一ソースで実測しました(各結果はケースの verification/probes.txt に記録)。名前空間が javax から jakarta へ 移ったこと自体は、Jakarta EE 9 以降の名前空間変更に沿っています。

検証(machine-verified)

この修正は eclipse-temurin:17-jdk のバージョン固定コンテナ内で再現し、修正後に package javax.persistence does not exist のシグネチャが消えることを機械で確認しています。

verify — run-case.mjs
$ node run-case.mjs jvm/spring-boot3-javax-persistence
● reproduce package javax.persistence does not exist present ✓
● apply fix exit 0
● re-run package javax.persistence does not exist gone ✓
PASS verified · eclipse-temurin:17-jdk · signature gone