Spring Boot 3 以降でこのエラーが出るのは、サーブレットや JPA などの Java EE の API が、パッケージ名 javax.* から jakarta.* に変わったためです。 コードの import javax.servlet... を import jakarta.servlet... に、依存ライブラリを Jakarta 版に置き換えると直ります。

// 変更前(Spring Boot 2.x まで)
import javax.servlet.http.HttpServletRequest;
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;

// 変更後(Spring Boot 3.x・4.x)
import jakarta.servlet.http.HttpServletRequest;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;

ただし、javax を全部 jakarta に一括置換してはいけません。 javax.sql.DataSource や javax.crypto.Cipher のように JDK に含まれる javax はそのまま残ります。この記事では、移るパッケージと残るパッケージの一覧、依存ライブラリの置き換え表、設定ファイルの書き換え、そして JDK の javax を壊さずに書き換えるスクリプトを、実行結果つきでまとめました。

確認環境:OpenJDK 21.0.10(javac で再現)、Python 3.11(書き換えスクリプト)。Spring Boot は 4.1.1 の公式ドキュメント、OpenRewrite は公式ドキュメントで確認(確認日 2026年10月10日)。

なぜ jakarta に変わったのか(30秒で)

Java EE は Oracle から Eclipse Foundation に移管されて「Jakarta EE」になり、商標の都合で javax の名前空間を新しい仕様に使えなくなりました。そのため Jakarta EE 9 でパッケージ名が jakarta.* に一斉に変わり、Spring Boot 3.0(Spring Framework 6)からはこの Jakarta 版が前提になりました。

Spring Boot Spring Framework パッケージ Java サーブレット
2.7 まで 5.3 javax.*(Java EE 8) 8 以上 Servlet 4.0(Tomcat 9)
3.x 6.x jakarta.*(Jakarta EE 9〜10) 17 以上 Tomcat 10.1(Servlet 6.0)など
4.x(4.1.1 時点) 7.0 jakarta.* 17 以上(26 まで対応) Servlet 6.1 以上(Tomcat 11.0、Jetty 12.1)

Spring Boot 2 から 4 へ上げる場合も、javax → jakarta の作業は同じです。3 を経由して段階的に上げると、エラーの原因を切り分けやすくなります。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「javax.servlet does not existの直し方|jakarta移行」

エラーの出方

依存ライブラリを Jakarta 版に替えたあと、javax のままのコードをコンパイルすると次のように出ます。JDK 21 の javac で、Java EE 系の依存が無い状態を再現した結果です。

UserController.java:3: error: package javax.annotation does not exist
import javax.annotation.PostConstruct;
                       ^
UserController.java:6: error: package javax.persistence does not exist
import javax.persistence.Entity;
                        ^
UserController.java:8: error: package javax.servlet.http does not exist
import javax.servlet.http.HttpServletRequest;
                         ^
UserController.java:10: error: package javax.validation.constraints does not exist
import javax.validation.constraints.NotNull;
                                   ^
UserController.java:11: error: package javax.xml.bind.annotation does not exist
import javax.xml.bind.annotation.XmlRootElement;
                                ^
UserController.java:17: error: cannot find symbol
    String path(HttpServletRequest req) { return req.getRequestURI(); }
                ^
  symbol:   class HttpServletRequest

同じファイルにあった javax.annotation.processing.Processor、javax.crypto.Cipher、javax.sql.DataSource、javax.xml.parsers.DocumentBuilderFactory はエラーになっていません。これらは JDK に含まれているので、jakarta に変えてはいけない側です。

エラーの種類 例 原因
コンパイルエラー package javax.servlet does not exist、package javax.persistence does not exist 自分のコードの import が javax のまま
起動時のエラー ClassNotFoundException: javax.servlet.Filter、NoClassDefFoundError: javax/servlet/http/HttpServletRequest 使っている外部ライブラリが javax のまま(Jakarta 版に替えていない)
エラーなしで動かない @NotNull が効かない、@PostConstruct が呼ばれない javax の注釈が残っていて、Jakarta 版の仕組みに無視されている

3つ目がいちばん見落としやすいので、移行後は入力チェックと初期化処理をテストで確かめます。

移るパッケージ・残るパッケージの一覧

jakarta に移る(Jakarta EE の仕様)

変更前 変更後 主な用途
javax.servlet.* jakarta.servlet.* サーブレット、フィルター、HttpServletRequest
javax.persistence.* jakarta.persistence.* JPA(@Entity、EntityManager)
javax.validation.* jakarta.validation.* Bean Validation(@NotNull、@Valid)
javax.annotation.*(PostConstruct、PreDestroy、Resource など) jakarta.annotation.* 共通の注釈
javax.transaction.*(Transactional など) jakarta.transaction.* JTA
javax.inject.* jakarta.inject.* @Inject
javax.mail.* jakarta.mail.* メール送信
javax.xml.bind.* jakarta.xml.bind.* JAXB(XML と Java の変換)
javax.xml.ws.*、javax.jws.*、javax.xml.soap.* jakarta.xml.ws.* ほか SOAP(JAX-WS)
javax.ws.rs.* jakarta.ws.rs.* JAX-RS
javax.websocket.* jakarta.websocket.* WebSocket
javax.json.* jakarta.json.* JSON-P/JSON-B
javax.el.*、javax.faces.*、javax.ejb.*、javax.jms.*、javax.enterprise.*、javax.interceptor.*、javax.activation.* jakarta.* EL、JSF、EJB、JMS、CDI ほか

javax のまま残る(JDK に含まれる)

パッケージ 主な用途
javax.sql.* DataSource
javax.crypto.* 暗号(Cipher、Mac)
javax.net.*、javax.net.ssl.* SSL・ソケット
javax.naming.* JNDI
javax.management.* JMX
javax.security.auth.*(message を除く)、javax.security.cert.* 認証
javax.xml.parsers.*、javax.xml.transform.*、javax.xml.xpath.*、javax.xml.stream.*、javax.xml.validation.*、javax.xml.namespace.*、javax.xml.datatype.* XML の解析・変換
javax.annotation.processing.* 注釈処理(コンパイラ用)
javax.transaction.xa.* XA トランザクション(JDK の java.transaction.xa)
javax.imageio.*、javax.swing.*、javax.sound.*、javax.print.*、javax.script.*、javax.tools.*、javax.lang.model.* 画像、画面、音声、印刷、スクリプト、コンパイラ

javax.annotation と javax.transaction は、同じ名前の下に「移るもの」と「残るもの」が混ざっています。 一括置換で事故が起きやすいのはこの2つです。

依存ライブラリの置き換え(Maven)

Spring Boot のスターターを使っているなら、スターター経由の依存は Spring Boot のバージョンを上げるだけで Jakarta 版になります。自分で直接書いた依存は、次のように置き換えます(バージョンは Spring Boot の依存管理に任せ、書かないのが基本です)。

変更前(javax) 変更後(jakarta)
javax.servlet:javax.servlet-api jakarta.servlet:jakarta.servlet-api
javax.persistence:javax.persistence-api jakarta.persistence:jakarta.persistence-api
javax.validation:validation-api jakarta.validation:jakarta.validation-api
javax.annotation:javax.annotation-api jakarta.annotation:jakarta.annotation-api
javax.transaction:javax.transaction-api jakarta.transaction:jakarta.transaction-api
javax.inject:javax.inject jakarta.inject:jakarta.inject-api
javax.xml.bind:jaxb-api jakarta.xml.bind:jakarta.xml.bind-api(実装は org.glassfish.jaxb:jaxb-runtime)
javax.mail:javax.mail-api、com.sun.mail:javax.mail jakarta.mail:jakarta.mail-api(実装は org.eclipse.angus:angus-mail)
org.hibernate:hibernate-core(5.x) org.hibernate.orm:hibernate-core(6.x 以降。グループ ID が変わる)
org.hibernate.validator:hibernate-validator(6.x) 同じ座標の 8.x 以降
<!-- 変更前 -->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

<!-- 変更後(Spring Boot の依存管理があるのでバージョンは省略) -->
<dependency>
  <groupId>jakarta.servlet</groupId>
  <artifactId>jakarta.servlet-api</artifactId>
  <scope>provided</scope>
</dependency>

javax 版の jar が依存に残っていると、コンパイルは通るのに実行時に動かない原因になります。mvn dependency:tree | grep javax(Gradle は gradle dependencies | grep javax)で、間接的に入っている javax 版を探します。

外部ライブラリの例

ライブラリ Spring Boot 3・4 での対応
Springfox(Swagger) Jakarta 版が無い。springdoc-openapi 2.x 以降へ移行
Thymeleaf の Spring Security 連携 thymeleaf-extras-springsecurity5 → thymeleaf-extras-springsecurity6
Ehcache 3 Jakarta 版(classifier に jakarta)を使う
Tomcat に WAR でデプロイ Tomcat 9 は javax。Spring Boot 3 は Tomcat 10.1 以降、4 は Tomcat 11 以降
社内の共通ライブラリ javax を使っているなら Jakarta 版を作る(下の Eclipse Transformer も選択肢)

設定ファイルの書き換え

import だけでなく、文字列や XML にも javax が出てきます。

ファイル 変更前 変更後
persistence.xml の名前空間 http://xmlns.jcp.org/xml/ns/persistence https://jakarta.ee/xml/ns/persistence(version も 3.0 以上に)
JPA のプロパティ javax.persistence.jdbc.url など jakarta.persistence.jdbc.url など
application.properties spring.jpa.properties.javax.persistence.* spring.jpa.properties.jakarta.persistence.*
web.xml の名前空間 http://xmlns.jcp.org/xml/ns/javaee https://jakarta.ee/xml/ns/jakartaee(version は 5.0 以上)
JSP の taglib http://java.sun.com/jsp/jstl/core jakarta.tags.core(JSTL 3.0)
META-INF/services/javax.* ファイル名が javax.… ファイル名を jakarta.… に

自動で書き換える方法

方法 向いている場面 特徴
OpenRewrite Maven・Gradle のプロジェクト全体 型を見て書き換える。依存の置き換えまで行うレシピがある
IntelliJ IDEA IDE で確認しながら 「Refactor」→「Migrate Packages and Classes」→「Java EE to Jakarta EE」
この記事のスクリプト ビルドツールが使えない・まず影響範囲を知りたい JDK の javax を除外して一覧表示、--apply で書き換え
Eclipse Transformer ソースの無い jar(javax のままの社外ライブラリ) jar のバイトコードの javax を jakarta に変換する

OpenRewrite(Maven)

プロジェクトのフォルダで実行します。dryRun にすると変更内容だけを target/rewrite/rewrite.patch に出力します。

mvn -U org.openrewrite.maven:rewrite-maven-plugin:dryRun \
  -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:RELEASE \
  -Drewrite.activeRecipes=org.openrewrite.java.migrate.jakarta.JavaxMigrationToJakarta

内容を確認したら、dryRun を run に替えて適用します。Spring Boot 自体のバージョンも上げる場合は、rewrite-spring の org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 のようなレシピを使うと、javax → jakarta を含めて一度に書き換えます。

JDK の javax を壊さない書き換えスクリプト

ビルドを動かさずに影響範囲を一覧したいときは、次の Python スクリプトが使えます。上の「移る」一覧だけを書き換え、javax.annotation.processing と javax.transaction.xa は残します。XML の名前空間も書き換えます。

"""javax → jakarta の書き換え対象を洗い出し、--apply で書き換える(JDK に残る javax は変えない)

使い方:
  python3 jakarta_migrate.py src            # 対象の一覧だけ表示(変更しない)
  python3 jakarta_migrate.py src --apply    # 書き換える(先に Git でコミットしておく)
"""
import re
import sys
from pathlib import Path

# jakarta へ移るパッケージ(Jakarta EE の仕様)
MOVE = ['activation', 'annotation', 'batch', 'decorator', 'ejb', 'el', 'enterprise',
        'faces', 'inject', 'interceptor', 'jms', 'json', 'jws', 'mail', 'persistence',
        'resource', 'security.auth.message', 'security.enterprise', 'security.jacc',
        'servlet', 'transaction', 'validation', 'websocket', 'ws.rs', 'xml.bind',
        'xml.soap', 'xml.ws']
# javax のまま残るもの(JDK に含まれる)のうち、上の名前と前方一致してしまうもの
KEEP = ['javax.annotation.processing', 'javax.transaction.xa']

PKG = re.compile(r'\bjavax\.(' + '|'.join(re.escape(m) for m in sorted(MOVE, key=len, reverse=True)) + r')(?=[.;\s"*<>]|$)')
XML_NS = {
    'http://xmlns.jcp.org/xml/ns/javaee': 'https://jakarta.ee/xml/ns/jakartaee',
    'http://xmlns.jcp.org/xml/ns/persistence': 'https://jakarta.ee/xml/ns/persistence',
    'http://java.sun.com/xml/ns/javaee': 'https://jakarta.ee/xml/ns/jakartaee',
}
TARGET = {'.java', '.kt', '.xml', '.properties', '.yml', '.yaml', '.jsp', '.tag', '.groovy'}

def convert(line: str) -> str:
    def repl(m):
        start = m.start()
        if any(line.startswith(k, start) for k in KEEP):
            return m.group(0)
        return 'jakarta.' + m.group(1)
    new = PKG.sub(repl, line)
    for old, nw in XML_NS.items():
        new = new.replace(old, nw)
    return new

def main(root: str, apply: bool) -> None:
    files = changed = 0
    for path in sorted(Path(root).rglob('*')):
        if path.suffix not in TARGET and 'META-INF/services' not in path.as_posix():
            continue
        if not path.is_file():
            continue
        lines = path.read_text(encoding='utf-8').splitlines(keepends=True)
        out, hits = [], []
        for no, line in enumerate(lines, 1):
            new = convert(line)
            if new != line:
                hits.append((no, line.strip(), new.strip()))
            out.append(new)
        if hits:
            files += 1
            changed += len(hits)
            print(f'== {path}')
            for no, old, new in hits:
                print(f'  {no:>4}: {old}\n        → {new}')
            if apply:
                path.write_text(''.join(out), encoding='utf-8')
        # サービス定義ファイルは、ファイル名自体が javax.* のことがある
        if 'META-INF/services' in path.as_posix() and PKG.match(path.name):
            print(f'== ファイル名の変更が必要: {path.name} → {convert(path.name)}')
    print(f'\n{files} ファイル・{changed} 行が対象' + ('(書き換えました)' if apply else '(--apply で書き換え)'))

if __name__ == '__main__':
    main(sys.argv[1] if len(sys.argv) > 1 else 'src', '--apply' in sys.argv)

最初に、変更せず一覧だけを出します。

$ python3 jakarta_migrate.py src
== src/main/java/com/example/UserController.java
     3: import javax.annotation.PostConstruct;
        → import jakarta.annotation.PostConstruct;
     6: import javax.persistence.Entity;
        → import jakarta.persistence.Entity;
     7: import javax.persistence.Id;
        → import jakarta.persistence.Id;
     8: import javax.servlet.http.HttpServletRequest;
        → import jakarta.servlet.http.HttpServletRequest;
    10: import javax.validation.constraints.NotNull;
        → import jakarta.validation.constraints.NotNull;
    11: import javax.xml.bind.annotation.XmlRootElement;
        → import jakarta.xml.bind.annotation.XmlRootElement;
== src/main/resources/META-INF/persistence.xml
     1: <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
        → <persistence xmlns="https://jakarta.ee/xml/ns/persistence" version="2.2">
     4: <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/app"/>
        → <property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://localhost/app"/>
== src/main/resources/application.properties
     1: javax.persistence.lock.timeout=3000
        → jakarta.persistence.lock.timeout=3000

3 ファイル・9 行が対象(--apply で書き換え)

Git でコミットしてから --apply で書き換え、残った javax を確認します。

$ python3 jakarta_migrate.py src --apply
3 ファイル・9 行が対象(書き換えました)

$ grep -rn "javax" src
src/main/java/com/example/UserController.java:4:import javax.annotation.processing.Processor;
src/main/java/com/example/UserController.java:5:import javax.crypto.Cipher;
src/main/java/com/example/UserController.java:9:import javax.sql.DataSource;
src/main/java/com/example/UserController.java:12:import javax.xml.parsers.DocumentBuilderFactory;

残ったのは JDK に含まれる4つだけです。persistence.xml の version="2.2" はスクリプトでは変えないので、3.0 以上に手で直します(Spring Boot 3・4 の Hibernate 6・7 が読む版にそろえます)。

移行の手順とチェックリスト

順番 作業 確認すること
1 Java を 17 以上にする java -version、ビルドの release 設定
2 Spring Boot 2.7 の最新にして、非推奨の警告を消す ビルドの警告が0件か
3 Spring Boot を 3.x(または 4.x)に上げる spring-boot-properties-migrator を一時的に入れ、名前が変わった設定キーの警告を見る
4 javax → jakarta を書き換える OpenRewrite かスクリプトで一覧 → 適用
5 直接書いた依存を Jakarta 版に置き換える dependency:tree に javax の Java EE 系 jar が残っていないか
6 外部ライブラリを Jakarta 対応版に上げる Springfox → springdoc など
7 設定ファイル・XML・JSP を書き換える grep -rn "javax\.\(persistence|servlet|validation\)" src
8 テストで動きを確かめる 入力チェック(@NotNull)、@PostConstruct、フィルター、トランザクションが効いているか

よくある質問

Q. javax を jakarta に一括置換してもよいですか。 A. 避けたほうが安全です。javax.sql.DataSource、javax.crypto、javax.net.ssl、javax.xml.parsers、javax.annotation.processing などは JDK にあり、jakarta にすると今度はそちらがコンパイルエラーになります。この記事の「移る」一覧に入っているパッケージだけを置き換えます。

Q. コンパイルは通るのに、入力チェックが効かなくなりました。 A. javax.validation の注釈がどこかに残っている可能性があります。Spring Boot 3 以降の Hibernate Validator は jakarta.validation の注釈を読むため、javax の注釈は無視されます。grep -rn "javax.validation" src で探し、依存からも javax 版の validation-api を外します。

Q. 社外のライブラリが javax のままで、Jakarta 版がありません。 A. 新しい版や代わりのライブラリがあるかを先に確認します。無い場合は、Eclipse Transformer で jar の javax を jakarta に変換する方法があります。変換した jar は動作の確認と、ライセンス上の扱いの確認が必要です。

Q. Spring Boot 2 から 4 に直接上げられますか。 A. 上げられますが、javax → jakarta、設定キーの変更、Spring Security の書き方の変更、Boot 4 での変更(スターター名の変更など)が一度に来ます。3.x を経由し、段階ごとにテストを通すほうが、どこで壊れたかを切り分けやすくなります。

まとめ

  • エラーの原因は、Spring Boot 3 以降で Java EE の API が javax.* → jakarta.* に変わったこと
  • 一括置換はしない。javax.sql・javax.crypto・javax.net.ssl・javax.xml.parsers・javax.annotation.processing などは JDK に残る
  • 依存も Jakarta 版に替える。javax 版の jar が残ると、起動時エラーや「注釈が黙って無視される」原因になる
  • XML の名前空間、javax.persistence.* の設定キー、META-INF/services のファイル名も書き換える
  • OpenRewrite の JavaxMigrationToJakarta か、この記事のスクリプトで一覧を出してから適用する
  • 移行後は 入力チェック・@PostConstruct・フィルター・トランザクション をテストで確かめる

参考・出典

確認日はいずれも 2026年10月10日です。

  • Spring Boot「System Requirements」(4.1.1):https://docs.spring.io/spring-boot/system-requirements.html
  • Spring Boot「Spring Boot 3.0 Migration Guide」:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide
  • Spring Boot「Spring Boot 4.0 Migration Guide」:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide
  • Jakarta EE「Jakarta EE 9 Release Plan(パッケージ名の変更)」:https://jakarta.ee/specifications/platform/9/
  • OpenRewrite「Migrate to Jakarta EE 9(JavaxMigrationToJakarta)」:https://docs.openrewrite.org/recipes/java/migrate/jakarta/javaxmigrationtojakarta
  • IntelliJ IDEA ドキュメント「Migrate to Jakarta EE」:https://www.jetbrains.com/help/idea/jakarta-ee.html
  • Eclipse Transformer:https://github.com/eclipse/transformer
  • Java SE 21 API(モジュール一覧。JDK に含まれる javax パッケージ):https://docs.oracle.com/en/java/javase/21/docs/api/index.html
  • Viktar Patotski「javax to jakarta: Migrate Spring Boot 2 to 3 the Safe Way」:https://patotski.com/blog/spring-boot-3-javax-to-jakarta/

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「javax.servlet does not existの直し方|jakarta移行」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?