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、@Column、EntityManager など、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.18 の spring-boot-starter-data-jpa | 成功(終了コード 0) |
Spring Boot 3.2.12 の spring-boot-starter-data-jpa | package javax.persistence does not exist(終了コード 1) |
Spring Boot 3.2.12 + javax.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.annotationもjakarta.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 以降の名前空間変更に沿っています。