- JAVA
- Spring
javax.servlet does not existの直し方|jakarta移行
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期連続の黒字決算。