Javaのマイグレーションは、古いJDKやフレームワークで動くアプリケーションを、サポートが続く版へ移す作業です。作業は大きく2つに分かれます。JDK本体の版を上げる移行と、Spring BootやJakarta EEなどフレームワークの世代を上げる移行です。この記事では、2026年10月時点で移行先に選ぶLTS、移行前の調査コマンド、版をまたぐと壊れる箇所、フレームワーク移行の順序、OpenRewriteによる自動書き換えまでを、JDK 25(Temurin 25.0.4.1)で実行した出力を添えて整理します。
まとめ
- 移行先はJava 21か25のLTS:Oracle JDKのPremier Supportは17が2026年9月、21が2028年9月、25が2030年9月まで。17に留まる現場も、次の移行先は21か25で決める。
- JDKとフレームワークは同時に上げない:まず今のSpring Bootが対応するJDK(2.7.18なら21まで)へ上げて動かし、次にSpring Bootの世代を上げ、最後に必要なら25へ進む。同時に上げると、壊れた原因がどちらか切り分けにくい。
- 事前調査はjdepsとjdeprscan:内部API依存と削除予定APIをビルド前に洗い出す。ただしリフレクション経由の内部API利用はjdepsに出ず、実行時に
InaccessibleObjectExceptionで落ちる。 - Spring Boot 3以降はjavaxからjakartaへ:Spring Boot 3.0から最小Java 17・Jakarta EE名前空間。4.0はJakarta EE 11。2系からはまず3.5まで上げてから4系へ進む。
- 機械的な書き換えはOpenRewriteに任せる:
UpgradeToJava21・UpgradeToJava25・JavaxMigrationToJakartaなどのレシピで、ビルド設定と非推奨APIの置換を自動化できる。残った差分は人が直す。
Javaマイグレーションの対象範囲:JDK・フレームワーク・実行基盤・DB
「Javaマイグレーション」という言葉が指す範囲は現場によって違います。見積もりや計画の前に、どの層を動かすのかを決めておくと作業量を読み違えません。
| 層 | 移行の例 | 主な確認対象 |
|---|---|---|
| JDK本体 | Java 8 → 21 / 25 | 内部API・削除API・起動オプション |
| フレームワーク | Spring Boot 2.7 → 3.5 → 4.1 | javax→jakarta・設定プロパティ |
| EOLフレームワーク | Struts 1 / 2.5 → Spring MVC | 画面・Action単位の作り直し |
| 実行基盤 | Tomcat 9 → 10.1 / 11、WebLogic等 | Servlet仕様の版・名前空間 |
| DBスキーマ | Flyway / Liquibaseで版管理 | 移行スクリプトの順序と再実行 |
「Java フレームワーク マイグレーション」という言葉は、アプリのフレームワーク(Spring Boot・Struts)を新しい世代へ移す作業と、DBのスキーマ変更を版管理するマイグレーションフレームワーク(Flyway・Liquibase)の両方を指して使われます。この記事は前者を中心に扱い、後者は終盤の章で使い分けだけを示します。業務システム全体の移行方式(一括・段階・並行稼働)はシステム移行とは?移行方式の種類と進め方・失敗を防ぐ判断基準を解説で整理しています。
移行先バージョンの決め方:LTSとサポート期限
JDKのLTSとOracleのサポート期限
JDKは6か月ごとに新版が出て、2021年のJava 17以降は2年ごとにLTS(長期サポート版)が出ます。移行先には原則としてLTSを選びます。非LTSのJava 26は次の版が出た時点で無償の更新が終わるため、業務システムの移行先には向きません。
| 版 | GA | Oracle Premier | Oracle Extended |
|---|---|---|---|
| Java 8 | 2014年3月 | 2022年3月終了 | 2030年12月 |
| Java 11 | 2018年9月 | 2023年9月終了 | 2032年1月 |
| Java 17 | 2021年9月 | 2026年9月終了 | 2029年9月 |
| Java 21 | 2023年9月 | 2028年9月 | 2031年9月 |
| Java 25 | 2025年9月 | 2030年9月 | 2033年9月 |
期限はOracleのJava SE Support Roadmapによります。Eclipse TemurinやAmazon CorrettoなどOpenJDKのディストリビューションは、配布元ごとに更新期間が違います。どの配布を使うかと無償で使える範囲はOpenJDKは商用利用できる?無料の範囲とOracle JDKとの違い・ライセンス・サポート期限【2026年最新】にまとめています。
21と25のどちらを選ぶかは、使っているフレームワークとライブラリが25に対応しているかで決めます。Spring Boot 4.0.8・4.1.1はJava 26まで、3.5.16はJava 25まで対応しています。一方、Java 24でSecurity Managerが恒久的に無効化されたため、Security Managerに依存するライブラリが残っていると25へは上げられません。その場合は21を選び、依存の置き換えを並行して進めます。
Spring Bootの世代と必要なJava
フレームワークの移行先も、無償サポートの残り期間で選びます。Spring Bootは各マイナー版のOSSサポートが約12か月で、LTSの指定はありません。
| Spring Boot | 必要なJava | Jakarta EE | OSSサポート |
|---|---|---|---|
| 4.1 | 17〜26 | 11 | 2027年7月31日まで |
| 4.0 | 17〜26 | 11 | 2026年12月31日まで |
| 3.5 | 17〜25 | 9 / 10 | 2026年6月30日に終了 |
| 2.7 | 8〜21 | なし(javax) | 終了済み |
OSSサポートの終了日はSpring Boot公式のサポート表の値です。版ごとの最新パッチと商用サポートの期限はSpring Bootバージョン一覧とサポート期限【2026年8月】最新4.1と3.5 EOL後の選び方に載せています。2026年10月時点で無償サポートが残るのは4.0と4.1だけです。2.7や3.x系に残っているアプリは、4.1を最終目標に計画します。
JDKを上げる手順:jdeps・jdeprscanでの事前調査から
OracleのJDK 25移行ガイドは、作業を「新しいJDKの入手」「再コンパイルせずに実行」「サードパーティライブラリの更新」「必要ならコンパイル」「jdepsの実行」の順に並べ、移行は反復的な作業だと述べています。まず既存のビルド成果物を新しいJDKで動かし、出た警告とエラーから直す箇所を決める流れです。
再コンパイル前の起動確認と廃止オプションの検出
既存のjarやwarを新しいJDKのjavaでそのまま起動します。廃止された起動オプションは警告やエラーとして出るので、ここで起動スクリプトを洗います。JDK 9〜16で内部APIへのアクセスを許すために使われた--illegal-access=permitは、JDK 25では次のように無視されます。
$ java --illegal-access=permit -cp out Dep
OpenJDK 64-Bit Server VM warning: Ignoring option --illegal-access=permit; support was removed in 17.0
警告で済むため見落としやすい点に注意してください。このオプションに頼って動いていた処理は、JDK 17以降で実行時例外になります。
jdepsによるJDK内部API依存の検出
jdeps --jdk-internalsは、クラスファイルやjarが使っているJDK内部APIを一覧にし、置き換え先の候補も表示します。sun.security.x509.X500Nameを使うクラスに実行した結果です。
$ jdeps --jdk-internals in
in -> java.base
UsesSun -> sun.security.x509.X500Name JDK internal API (java.base)
JDK Internal API Suggested Replacement
---------------- ---------------------
sun.security.x509.X500Name Use javax.security.auth.x500.X500Principal @since 1.4
jdepsは静的解析なので、リフレクションで内部APIを呼ぶコードは検出しません。Oracleのガイドもこの限界を明記しています。リフレクション経由の利用は、後述の起動テストで拾います。
jdeprscanによる削除予定APIの検出
jdeprscanは非推奨APIの利用箇所を列挙します。--for-removalを付けると、削除予定(forRemoval=true)のものだけに絞れます。
$ jdeprscan --for-removal out
Directory out:
class Dep uses deprecated method java/lang/Runtime::runFinalization()V (forRemoval=true)
class Sm uses deprecated class java/lang/SecurityManager (forRemoval=true)
class Sm uses deprecated method java/lang/System::setSecurityManager(Ljava/lang/SecurityManager;)V (forRemoval=true)
--release 9〜--release 25を付けると、指定した版で非推奨になっているAPIを基準に調べられます(--release 8以前は--for-removalと併用できず、JDK 25では使い方の表示で終了します)。調べる対象はJava SEのAPIだけで、ライブラリ自身の非推奨は出ません。jdeprscanのマニュアルのとおり、依存jarを--class-pathで渡さないと、見つからないクラスごとにエラーが出ます。アプリの起動時と同じクラスパスを渡してください。
–releaseによる対象版の指定と再コンパイル
コンパイルには-source・-targetではなく--releaseを使います。--releaseは指定した版のAPIだけを参照してコンパイルするため、新しいJDKで古い版向けにビルドしても新しいAPIの混入を防げます。JDK 25で--release 8を指定すると、まだコンパイルはできますが次の警告が出ます。
$ javac --release 8 -d r8 Dep.java
warning: [options] source value 8 is obsolete and will be removed in a future release
warning: [options] target value 8 is obsolete and will be removed in a future release
Java 8向けのビルドを新しいJDKで続けられる期間は限られます。Mavenならmaven.compiler.release、Gradleならoptions.releaseを移行先の版にそろえます。
版をまたぐと壊れる箇所:JDK 11・17・24の変更点
Java 8から21・25へ上げるときに止まりやすい変更の代表例です。これ以外にも、ロケールデータの既定変更や起動オプションの廃止などで挙動が変わることがあるため、各版の移行ガイドも併せて確認します。
| 版 | 変更 | JEP | 典型的な症状 |
|---|---|---|---|
| JDK 11 | Java EE・CORBAモジュール削除 | 320 | javax.xml.bind が見つからない |
| JDK 17 | JDK内部の強いカプセル化 | 403 | InaccessibleObjectException |
| JDK 15 | Nashorn JavaScriptエンジン削除 | 372 | ScriptEngine が null |
| JDK 18 | 既定の文字コードがUTF-8 | 400 | Windowsで文字コード未指定の読み書きが化ける |
| JDK 24 | Security Managerの恒久的な無効化 | 486 | UnsupportedOperationException |
JDK 11:JAXBなどJava EEモジュールの削除
JEP 320で、JAXB(javax.xml.bind)・JAX-WS・JAF・CORBAなどがJDKから取り除かれました。Java 8で動いていたコードをJDK 25でコンパイルすると、次のエラーになります。
Legacy.java:1: error: package javax.xml.bind does not exist
import javax.xml.bind.DatatypeConverter;
対処は3通りです。この例のような16進やBase64の変換は、java.util.HexFormat(JDK 17以降)やjava.util.Base64へ置き換えます。javax.xml.bindのままXMLバインディングを使い続けるなら、javax名前空間を持つ2.3系のAPIと実装(jakarta.xml.bind-api 2.3.3とjaxb-runtime 2.3系)を依存に加えます。Jakarta XML Binding 3.0以降はパッケージがjakarta.xml.bindに変わるため、依存の追加に加えてimportの書き換えが必要です。
JDK 17:内部APIの強いカプセル化
JEP 403以降、JDK内部の非公開フィールドへのリフレクションは既定で拒否されます。Stringの内部配列にsetAccessible(true)するコードは、コンパイルは通り、実行時に落ちます。
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field private final byte[] java.lang.String.value accessible: module java.base does not "opens java.lang" to unnamed module @7fbe847c
起動時に--add-opens java.base/java.lang=ALL-UNNAMEDを付ければ動きます。ただしこれは一時しのぎです。多くの場合、原因は古い版のライブラリ(シリアライザやモックライブラリなど)なので、ライブラリを上げて--add-opensを外すのが本来の対処です。モジュールの公開範囲の仕組みはJavaモジュールシステムとは?module-info.javaの書き方とパッケージとの違いで解説しています。
JDK 24:Security Managerの恒久的な無効化
JEP 486により、JDK 24以降はSecurity Managerを有効にできません。JDK 25でSystem.setSecurityManagerを呼ぶとUnsupportedOperationException: Setting a Security Manager is not supportedになり、起動オプション-Djava.security.manager=allowを付けるとVM自体が起動しません。
Error occurred during initialization of VM
java.lang.Error: A command line option has attempted to allow or enable the Security Manager. Enabling a Security Manager is not supported.
Security Managerでプラグインやスクリプトの権限を絞っていたアプリは、コンテナやOSの権限分離など別の仕組みへ置き換える必要があります。この作業が間に合わないなら、移行先は21にします。
フレームワークの移行:javaxからjakarta、Spring Boot 2→3→4
Spring Boot 3で起きるjavaxからjakartaへの名前空間変更
Spring Boot 3.0(2022年11月)で、最小要件がJava 17になり、Servlet・JPA・Bean Validationなどのパッケージがjavax.*からjakarta.*へ変わりました。import javax.persistence.Entity;はimport jakarta.persistence.Entity;に書き換えが必要です。
手作業の一括置換は危険です。JDK標準のjavax.sqlやjavax.cryptoはjakartaへ移っていないため、javax.を機械的に置換すると逆に壊れます。名前空間の変更は、対象パッケージを把握しているOpenRewriteのレシピ(後述)に任せるのが安全です。実行基盤も同時に影響を受けます。warを外部のアプリケーションサーバーへ置く場合、Spring Boot 3.5の動作要件はServlet 5.0以上(Tomcat 10系以降)で、javax名前空間のTomcat 9では動きません。
Spring Boot 4への移行と設定プロパティの確認
Spring Boot 4.0(2025年11月)はSpring Framework 7・Jakarta EE 11を土台にしています。2.7から4.1へ直接上げず、3.5で一度動かしてから4系へ進みます。Spring Boot 4.0の移行ガイドも、最初に3.5系の最新版へ上げ、4.0で削除される非推奨メソッドの呼び出しを見直すよう求めています。4系はServlet 6.1が前提になり、組み込みコンテナはTomcat 11.0系かJetty 12.1系です。Servlet 6.1に対応していないUndertowは4.0で外されたため、Undertowを使っているアプリはコンテナの載せ替えも作業に含まれます。
設定プロパティの名前変更は、spring-boot-properties-migratorを一時的に依存へ加えると、起動時に旧名のプロパティを検出してログに出し、実行時だけ新名へ読み替えます。移行が終わったら依存から外します。4系で変わった点の詳細はSpring Boot 4とは?最新バージョン4.1の変更点・新機能とSpring Boot 3との違いを解説【2026年最新】にあります。
StrutsなどEOLフレームワークからの移行
Apache Strutsの公式EOL一覧では、EOL日をStruts 1.xが2013年4月5日、2.3.xが2019年9月12日、2.5.xが2023年10月30日としています。2.5.xについては、同日付のEOL告知が「6か月後にEOLとなり、その間はセキュリティ対応を続ける」としていました。いずれの系統も、現在は修正版が出ません。2.5系はStruts 6・7系への版上げという選択肢もありますが、Struts 1はAPIが別物のため、Spring MVCなどへの作り替えになります。いずれもJDK移行とは別のプロジェクトとして計画します。ActionやActionFormをSpringの部品に対応づける方法はStrutsからSpring MVCへの移行|違い・手順・注意点を実装目線で解説で扱っています。
OpenRewriteによるコードとビルド設定の自動書き換え
OpenRewriteは、ソースコードとビルドファイルを「レシピ」単位で書き換えるツールです。Java移行用のレシピはrewrite-migrate-javaに入っています。Mavenなら、pom.xmlを変更せずに次のコマンドで実行できます。
mvn org.openrewrite.maven:rewrite-maven-plugin:6.46.1:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:3.42.1 \
-Drewrite.activeRecipes=org.openrewrite.java.migrate.UpgradeToJava21
Java 8向けの小さなプロジェクトにUpgradeToJava21を実行すると(rewrite-maven-plugin 6.46.1、rewrite-migrate-java 3.42.1)、pom.xmlのmaven.compiler.source・targetが1.8から21に変わり、ソースは次のように書き換わりました。
- Integer a = new Integer(1);
- Long b = new Long(2L);
+ Integer a = Integer.valueOf(1);
+ Long b = Long.valueOf(2L);
同じファイルにあったThread.currentThread().getId()(JDK 19で非推奨)は書き換わらずに残りました。レシピは全部を直すわけではありません。実行後はgit diffで差分を確認し、残った非推奨APIはjdeprscanで拾って手で直します。
OpenRewriteのような決定的な書き換えで済む部分と、生成AIに任せる部分(レシピで直らない箇所の修正案やテストの生成)の分担は、生成AIモダナイゼーションの実装手順で整理しています。
| 目的 | レシピ名 |
|---|---|
| Java 17へ | org.openrewrite.java.migrate.UpgradeToJava17 |
| Java 21へ | org.openrewrite.java.migrate.UpgradeToJava21 |
| Java 25へ | org.openrewrite.java.migrate.UpgradeToJava25 |
| javax→jakarta | org.openrewrite.java.migrate.jakarta.JavaxMigrationToJakarta |
| Spring Boot 4.0へ | org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0 |
レシピは前の版のレシピを内包しています。UpgradeToJava21はUpgradeToJava17を、UpgradeToJava25はSecurity Managerの呼び出しを取り除くRemoveSecurityManagerを含みます。8から一気に25のレシピを当てると差分が大きくなりすぎるため、レビューできる大きさに区切って版ごとにコミットします。Spring Boot 4.0のレシピはrewrite-springに入っており、レシピの説明によれば3.5へのレシピを内包しています。
レシピの配布元とライセンスの確認
導入前に2点を確かめてください。1点目は配布元です。OpenRewriteのドキュメントは、プラグインを含む成果物を認証付きのCode Genome Projectリポジトリから配布すると案内しており、Maven Centralからの移行を告知しています。2026年10月時点でMaven Centralから取得できる最新は、上の実行で使ったrewrite-maven-plugin 6.46.1とrewrite-migrate-java 3.42.1です。OpenRewriteのプラグイン設定の説明では、Code Genome Projectからの取得にはサインインして発行するトークンが必要で、Apacheライセンスのレシピは認証済みの誰でも、ソースアベイラブルのレシピはModerneのサブスクリプションがある場合に取得できるとされています。
2点目はライセンスです。UpgradeToJava21・UpgradeToJava25・JavaxMigrationToJakartaのいずれも、Apache 2.0ではなくModerne Source Available Licenseです。自社内での利用・複製・改変は許されていますが、レシピの機能を第三者へサービスとして提供することは制限されています。自社のアプリを自社で移行するなら問題になりにくい一方、移行作業を受託する側がレシピを使う場合は、契約前に条項を確認してください。
DBマイグレーションツール(Flyway・Liquibase)の位置づけ
FlywayとLiquibaseは、アプリの移行ではなくデータベースのスキーマ変更を版管理する仕組みで、JDKの移行に必須ではありません。移行と同時にスキーマも変えるなら導入を検討します。SQLファイルにV1__init.sqlのような番号を付けて順に流すだけで足りるならFlyway、XML・YAMLのchangesetで複数のDB製品へ同じ変更を流すならLiquibaseです。Liquibaseは5.0からライセンスがApache 2.0からFunctional Source Licenseへ変わった点も選定時に確認します。Spring BootでのFlywayの設定と命名規則はFlywayとは?Spring Bootのマイグレーション設定と命名規則・Spring Boot 4の変更点【2026年8月】で解説しています。
移行を止める失敗パターンと進める順序
変更を一度に重ねると、テストが落ちたときに原因を切り分けにくくなります。目安として次の順で進め、各段階でテストを通してから次へ進みます。ただしOracleのガイドが言うとおり移行は反復作業で、ライブラリの対応状況によっては中間の版を経由したり、順序を入れ替えたりする必要があります。
- ビルドツールとプラグインを新しいJDKに対応する版へ上げる(Maven Compiler Plugin・Surefire・Lombokなど)
- 今のフレームワークが対応する範囲でJDKを上げて、既存のテストを通す(Spring Boot 2.7.18ならJava 21まで)
- ライブラリを上げて
--add-opensを外す - Spring Bootの世代を1段ずつ上げる(2.7→3.5→4.1)
- 本番相当の負荷で起動とGCの挙動を確かめてから切り替える
手順2と4を同時に進めると、JDK 21とSpring Boot 3を同時に入れた状態でテストが落ちたとき、どれがJDK起因でどれがjakarta起因かを1件ずつ調べることになります。
もう1つの失敗は、--add-opensを起動スクリプトに積み上げて動かした状態を「移行完了」とすることです。次の版で開かれていないパッケージに触れて再び止まります。--add-opensが必要な箇所は、原因のライブラリと版を記録し、置き換えの期限を決めておきます。
リフレクション経由の内部API利用はjdepsに出ないため、静的解析だけで調査を終えないでください。単体テストのカバレッジが低いアプリでは、本番相当の画面操作やバッチ実行を新しいJDKで一巡させ、InaccessibleObjectExceptionがログに出ないことを確かめます。テストが薄く、移行範囲も読めない古い業務システムでは、移行に入る前にテストを書く工程を見積もりに入れます。設計からの刷新を含めて検討する場合は、システムマイグレーション・リプレイスの支援も相談先の1つです。
よくある質問
Java 8から21へ直接上げられますか?
上げられます。JDKは8から21へ直接入れ替えてかまいません。ただしコードは、JDK 11で削除されたJava EEモジュールと、JDK 17の強いカプセル化の両方に対応させる必要があります。書き換えのコミットを版ごとに分けておくと、問題が出たときに戻す範囲を小さくできます。
Javaの移行に使えるツールには何がありますか?
調査にはJDKに同梱のjdeps(内部API依存)とjdeprscan(非推奨・削除予定API)を使います。コードとビルド設定の書き換えにはOpenRewriteのレシピ、Spring Bootの設定プロパティ名の確認にはspring-boot-properties-migratorが使えます。DBスキーマの版管理が目的ならFlywayかLiquibaseです。どれも書き換えや検出を補助するだけで、実行時にしか出ない不具合は新しいJDKでの起動テストで拾います。
javaxからjakartaへの書き換えは一括置換でよいですか?
おすすめしません。javax.sql・javax.crypto・javax.netなどJDK標準のパッケージはjakartaへ移っていないため、文字列の一括置換ではこれらまで壊れます。OpenRewriteのJavaxMigrationToJakartaレシピは移行対象のパッケージだけを書き換え、依存ライブラリの座標も変更します。
移行にはどのくらいの期間がかかりますか?
アプリの規模より、内部APIへの依存とテストの厚さで決まります。jdepsとjdeprscanの結果が少なく、テストが揃っていれば、JDKの入れ替えは数日で終わることもあります。Spring Boot 2.7から4系への移行や、Strutsからの作り替えを含む場合は別の計画になります。見積もりの前に、jdepsとjdeprscanを全モジュールに実行して件数を把握してください。
古いJavaのまま使い続けるとどうなりますか?
アプリはそのまま動きますが、更新を受けられるかどうかは配布元と版で決まります。OracleのJava 8はPremier Supportが2022年3月に終わり、以降の更新はExtended Supportの有償契約が前提です。一方、Amazon Corretto 8のように、同じ版の更新を無償で続けている配布もあります。フレームワークは別で、Spring Boot 2.7のOSSサポートは2023年6月30日に終わっています。更新を受け続ける選択肢は、更新が続く配布への切り替え、有償の延長サポート、移行の3つで、フレームワークまで含めて更新を受けるには移行が必要です。