Spring Boot 4への移行とは、3.5系の最新版で非推奨の警告をなくしたうえで、スターターの細分化・Jackson 3・テスト用アノテーションの変更に順番に対応していく作業です。 一度に全部を直すのではなく、公式が用意している「classic スターター」を足場にして、ビルドが通る状態を保ったまま段階的に進められます。

この記事では、公式の Spring Boot 4.0 Migration Guide の章立てに沿って変更点を一覧にし、それぞれが「コンパイルで分かる/テストで分かる/黙って挙動が変わる」のどれに当たるかを列で示します。旧名と新名の対応表、世代別のサポート期限、3 系の書き方を探すスクリプト(出力つき)、そのまま貼れるチェックリストもまとめました。

確認環境:Spring Boot 4.1.1/3.5.16 の公式リファレンスと Migration Guide・4.1 Release Notes で確認(確認日 2026年10月7日)。検出スクリプトは Ubuntu 24.04・Python 3.11.15 で実行しています。

Spring Boot 4移行の早見表

順 やること 完了の目安
1 3.5系の最新版(3.5.16)へ上げる ビルドとテストが通る
2 非推奨の警告を解消する コンパイル時の非推奨警告が 0 件
3 classic スターターで 4.1.1 に上げる コンパイルが通る
4 スターターを技術ごとに置き換える classic を外しても起動する
5 Jackson 3 に合わせる JSON の入出力テストが通る
6 テストのアノテーションを直す 全テストが通る

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

(記載例)出典:株式会社RJC「Spring Boot 4移行の手順|3から4の変更点一覧とチェックリスト」

いつまでに上げるかをサポート期限から決める

3.5系の無償(OSS)サポートは 2026年6月30日に終了しており、4.0系も 2026年12月31日までです。 これから移行するなら、行き先は 4.1系(OSS サポート 2027年7月31日まで)にするのが素直です。下の表は api.spring.io の世代一覧から、3.4 以降を抜き出したものです(確認日 2026年10月7日)。

世代 初回リリース OSS 終了 商用終了
3.4.x 2024-11-30 2025-12-31 2026-12-31
3.5.x 2025-05-31 2026-06-30 2032-06-30
4.0.x 2025-11-30 2026-12-31 2027-12-31
4.1.x 2026-06-30 2027-07-31 2028-07-31
4.2.x 2026-11-30 2027-12-31 2028-12-31

公式のサポート方針では、メジャー版はリリースから少なくとも3年、マイナー版は少なくとも12か月サポートされ、新しいメジャー・マイナーはおよそ半年ごと(5月と11月)に出ます。この周期を前提に、次のように決めると迷いません。

今の状態 進め方の目安
3.4 以前を使っている まず 3.5.16 へ。ここまでは 3 系の中の更新
3.5 を OSS 版で使っている OSS の修正提供は終了済み。4.1 への移行を計画に入れる
3.5 を商用サポートで使っている 2032-06-30 まで期間がある。移行は機能追加の区切りに合わせられる
4.0 を使っている 2026-12-31 までに 4.1 へ。変更点は少ない(後述)
これから 4 系に上げる 4.1.1 を行き先にする。4.2 は 2026-11-30 の予定

3から4の変更点一覧(公式移行ガイドの章立て順)

「気づく場面」の列は、コンパイル=ビルドの時点でエラーになる、テスト=テストや起動で失敗として現れる、黙って=エラーにならずに動きだけが変わる、の3つで示します。「黙って」の行は、確認用のテストを先に書いてから上げると安心です。

要件

項目 4.0 の基準 気づく場面
Java 17 以上 コンパイル
Kotlin 2.2 以上 コンパイル
GraalVM native-image 25 以上 コンパイル
Jakarta EE 11 が基準 コンパイル
Servlet 6.1 が基準 テスト
Spring Framework 7.x コンパイル

4.1 では jOOQ の対応版が 3.20 になり、jOOQ を使う場合は Java 21 以上が必要です。

削除された機能

機能 4.0 での扱い 気づく場面
Undertow Servlet 6.1 に対応しないためスターターごと削除 コンパイル
Pulsar Reactive 自動構成を削除 コンパイル
起動スクリプト埋め込みの実行可能 JAR 削除。java -jar などで起動する テスト
Spring Session Hazelcast Boot からの直接サポートを削除 コンパイル
Spring Session MongoDB Boot からの直接サポートを削除 コンパイル
Spock 連携 Groovy 5 に対応していないため削除 コンパイル
CLASSIC ローダー loaderImplementation の設定ごと削除 コンパイル

モジュールとスターター

4.0 では自動構成が技術ごとの小さなモジュールに分かれました。命名は、モジュールが spring-boot-<技術>、スターターが spring-boot-starter-<技術>、テスト用が spring-boot-starter-<技術>-test です。

項目 3.x 4.x 気づく場面
Flyway flyway-core だけで動く spring-boot-starter-flyway が必要 黙って
Liquibase liquibase-core だけで動く spring-boot-starter-liquibase が必要 黙って
Web MVC spring-boot-starter-web spring-boot-starter-webmvc(旧名は非推奨で残る) コンパイル(警告)
AOP spring-boot-starter-aop spring-boot-starter-aspectj コンパイル
テスト用スターター spring-boot-starter-test 1つ 技術ごとの -test スターターを追加 コンパイル

Flyway と Liquibase を「黙って」としたのは、ライブラリ本体は残るのでコンパイルは通り、Boot 側の自動構成だけが外れるためです。起動時にテーブルができているかを確かめるテストがあると、ここで気づけます。

コア機能

項目 4.0 での変更 気づく場面
null 注釈 JSpecify の注釈を採用。org.springframework.lang からの移行を推奨 コンパイル
Logback の文字コード ファイル出力の既定が UTF-8 黙って
BootstrapRegistry org.springframework.boot.bootstrap へ移動 コンパイル
EnvironmentPostProcessor org.springframework.boot へ移動(旧も非推奨で残る) コンパイル(警告)
PropertyMapper null のとき変換・判定を呼ばない。必要なら always() 黙って
DevTools のライブリロード 既定で無効。spring.devtools.livereload.enabled=true で有効 黙って

依存関係とビルドプラグイン

項目 4.0 での変更 気づく場面
Maven の optional 依存 実行可能 JAR に含めない。必要なら <includeOptional>true</includeOptional> テスト
Spring Retry 依存管理から外れた。使い続けるなら版を明示 コンパイル
Spring Authorization Server Spring Security 7.0 に統合。spring-security.version で版を指定 コンパイル
CycloneDX Gradle プラグイン 3.0.0 以上 コンパイル
Hibernate hibernate-jpamodelgen は hibernate-processor へ コンパイル

Jackson 3

項目 3.x(Jackson 2) 4.x(Jackson 3) 気づく場面
パッケージ com.fasterxml.jackson tools.jackson(jackson-annotations は元のまま) コンパイル
カスタマイザー Jackson2ObjectMapperBuilderCustomizer JsonMapperBuilderCustomizer コンパイル
部品の登録 @JsonComponent/@JsonMixin @JacksonComponent/@JacksonMixin コンパイル
読み書きの設定 spring.jackson.read.*/write.* spring.jackson.json.read.*/json.write.* 黙って
モジュール登録 よく使われるものだけ自動 クラスパス上のすべてを自動登録 黙って

Actuator と Web

項目 4.0 での変更 気づく場面
エンドポイント引数の null 注釈 org.jspecify.annotations.Nullable を使う テスト
liveness/readiness 既定で有効。management.endpoint.health.probes.enabled=false で無効 黙って
静的リソース PathRequest#toStaticResources に /fonts/** が加わる 黙って
Spring Session の設定 spring.session.redis.* は spring.session.data.redis.* へ 黙って
HttpMessageConverters 非推奨。ClientHttpMessageConvertersCustomizer/ServerHttpMessageConvertersCustomizer へ コンパイル(警告)
server.forward-headers-strategy war 配備では効かない 黙って
war 配備の Tomcat spring-boot-starter-tomcat-runtime に変更 テスト

データ

項目 4.0 での変更 気づく場面
Elasticsearch Rest5Client に切り替え。Rest5ClientBuilderCustomizer を使う コンパイル
@EntityScan org.springframework.boot.persistence.autoconfigure.EntityScan コンパイル
例外変換の設定 spring.persistence.exceptiontranslation.enabled 黙って
MongoDB の接続設定 spring.data.mongodb.* の多くが spring.mongodb.* へ 黙って
MongoDB の UUID/BigDecimal 既定値がなくなり明示が必要 テスト

メッセージングとバッチ

項目 4.0 での変更 気づく場面
Kafka Streams StreamBuilderFactoryBeanCustomizer を削除。StreamsBuilderFactoryBeanConfigurer へ コンパイル
Kafka のリトライ spring.kafka.retry.topic.backoff.random は …backoff.jitter へ 黙って
AMQP のリトライ RabbitTemplateRetrySettingsCustomizer/RabbitListenerRetrySettingsCustomizer へ コンパイル
Spring Batch spring-boot-starter-batch はメモリ上で動く。DB に保存するなら spring-boot-starter-batch-jdbc 黙って

Spring Batch は影響が見えにくい変更です。スターター名をそのままにして上げると、ジョブのメタデータが既存のデータベースに保存されなくなります。履歴テーブルを参照している処理がある場合は、先に spring-boot-starter-batch-jdbc へ切り替えます。

テスト

項目 3.x 4.x 気づく場面
モック @MockBean/@SpyBean @MockitoBean/@MockitoSpyBean コンパイル
@Mock/@Captor MockitoTestExecutionListener が処理 MockitoExtension を付ける テスト
MockMvc @SpringBootTest だけで使える @AutoConfigureMockMvc を付ける テスト
TestRestTemplate @SpringBootTest だけで使える @AutoConfigureTestRestTemplate と依存2つ コンパイル
@PropertyMapping …test.autoconfigure.properties org.springframework.boot.test.context コンパイル

旧名から新名への対応表

スターター

旧(3.x) 新(4.x)
spring-boot-starter-web spring-boot-starter-webmvc
spring-boot-starter-web-services spring-boot-starter-webservices
spring-boot-starter-aop spring-boot-starter-aspectj
spring-boot-starter-oauth2-client spring-boot-starter-security-oauth2-client
spring-boot-starter-oauth2-resource-server spring-boot-starter-security-oauth2-resource-server
spring-boot-starter-oauth2-authorization-server spring-boot-starter-security-oauth2-authorization-server
flyway-core のみ spring-boot-starter-flyway
liquibase-core のみ spring-boot-starter-liquibase
spring-boot-starter-batch(DB 保存) spring-boot-starter-batch-jdbc
spring-boot-starter-tomcat(war 配備) spring-boot-starter-tomcat-runtime
spring-boot-starter-undertow spring-boot-starter-tomcat または spring-boot-starter-jetty

よく使うスターターとテスト用スターター

技術 本体 テスト用
Web MVC spring-boot-starter-webmvc spring-boot-starter-webmvc-test
WebFlux spring-boot-starter-webflux spring-boot-starter-webflux-test
RestClient/RestTemplate spring-boot-starter-restclient spring-boot-starter-restclient-test
WebClient spring-boot-starter-webclient spring-boot-starter-webclient-test
Validation spring-boot-starter-validation spring-boot-starter-validation-test
JDBC spring-boot-starter-jdbc spring-boot-starter-jdbc-test
Spring Data JPA spring-boot-starter-data-jpa spring-boot-starter-data-jpa-test
Spring Data Redis spring-boot-starter-data-redis spring-boot-starter-data-redis-test
Flyway spring-boot-starter-flyway spring-boot-starter-flyway-test
Liquibase spring-boot-starter-liquibase spring-boot-starter-liquibase-test
キャッシュ spring-boot-starter-cache spring-boot-starter-cache-test
Jackson spring-boot-starter-jackson spring-boot-starter-jackson-test
Security spring-boot-starter-security spring-boot-starter-security-test
Thymeleaf spring-boot-starter-thymeleaf spring-boot-starter-thymeleaf-test
Kafka spring-boot-starter-kafka spring-boot-starter-kafka-test
AMQP spring-boot-starter-amqp spring-boot-starter-amqp-test
Actuator spring-boot-starter-actuator spring-boot-starter-actuator-test

このほかの技術も同じ規則で名前が付いています。全件は公式移行ガイドの Starters の表にあります。

クラスとアノテーション

旧(3.x) 新(4.x)
com.fasterxml.jackson.databind.… tools.jackson.databind.…
Jackson2ObjectMapperBuilderCustomizer org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer
JsonObjectSerializer ObjectValueSerializer
JsonValueDeserializer ObjectValueDeserializer
@JsonComponent org.springframework.boot.jackson.JacksonComponent
@JsonMixin @JacksonMixin
@MockBean org.springframework.test.context.bean.override.mockito.MockitoBean
@SpyBean @MockitoSpyBean
org.springframework.boot.test.web.client.TestRestTemplate org.springframework.boot.resttestclient.TestRestTemplate
@AutoConfigureMockMvc(旧パッケージ) org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc
org.springframework.lang.Nullable org.jspecify.annotations.Nullable
RestClientBuilderCustomizer(Elasticsearch) Rest5ClientBuilderCustomizer
StreamBuilderFactoryBeanCustomizer StreamsBuilderFactoryBeanConfigurer
RabbitRetryTemplateCustomizer RabbitTemplateRetrySettingsCustomizer/RabbitListenerRetrySettingsCustomizer

設定プロパティ

旧(3.x) 新(4.x)
spring.jackson.read.* spring.jackson.json.read.*
spring.jackson.write.* spring.jackson.json.write.*
spring.jackson.parser.* spring.jackson.json.read.*
spring.session.redis.* spring.session.data.redis.*
spring.session.mongodb.* spring.session.data.mongodb.*
spring.data.mongodb.host など接続系 spring.mongodb.host など
management.health.mongo.* management.health.mongodb.*
management.metrics.mongo.* management.metrics.mongodb.*
spring.dao.exceptiontranslation.enabled spring.persistence.exceptiontranslation.enabled
spring.kafka.retry.topic.backoff.random spring.kafka.retry.topic.backoff.jitter
spring-authorization-server.version spring-security.version

4.0から4.1で加わる変更

4.0 を経由せずに 4.1.1 へ上げる場合は、次の点も合わせて確認します(4.1 Release Notes より)。

項目 4.1 での変更 気づく場面
4.0 で非推奨だったもの 削除 コンパイル
jarmode=layertools 削除。jarmode=tools を使う テスト
Maven の -DskipTests AOT 処理は省かれない。省くのは maven.test.skip 黙って
Derby 連携 非推奨。H2 や HSQL を検討 コンパイル(警告)
JPA の bootstrap-mode=deferred AsyncTaskExecutor の Bean が必要 テスト
jOOQ 3.20(Java 21 以上) コンパイル
DevTools の LiveReload 非推奨 コンパイル(警告)

Dockerfile で -Djarmode=layertools を使っている場合は、4.1 に上げる前に -Djarmode=tools へ書き換えておきます。

手順1と2:3.5最新版に上げて非推奨をなくす

3 系で非推奨だったクラス・メソッド・プロパティは 4.0 で削除されています。 先に 3.5.16 へ上げて警告を消しておくと、4 に上げたときのエラーが「4 で変わったこと」だけになり、原因を切り分けやすくなります。

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.5.16</version>
</parent>

非推奨の利用箇所は、コンパイラの -Xlint:deprecation で1件ずつ場所が出ます。付けない場合は「非推奨の API を使っています」という注記だけになります。Java 21 で、@Deprecated を付けたメソッドを呼ぶ2ファイルをコンパイルした出力です。

$ javac -cp out -d out Legacy.java
Note: Legacy.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

$ javac -Xlint:deprecation -cp out -d out Legacy.java
Legacy.java:3: warning: [deprecation] oldName() in OldApi has been deprecated
        System.out.println(OldApi.oldName());
                                 ^
1 warning

Maven や Gradle でも、コンパイラの引数にこのオプションを渡せば同じ形式で一覧が出ます。@MockBean のように「3.4.0 で非推奨、4.0.0 で削除」と API ドキュメントに書かれているものは、この段階で置き換えられます。

設定プロパティの名前変更は、公式が用意している spring-boot-properties-migrator を一時的に入れると、起動時に診断して実行時だけ読み替えてくれます。移行が終わったら外すのが前提の部品です。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-properties-migrator</artifactId>
  <scope>runtime</scope>
</dependency>
runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")

手順3:classicスターターで4に上げる

classic スターターは、すべてのモジュールをまとめて入れることで 3 系に近い構成を再現する足場です。 まずこれでビルドを通し、そのあとで技術ごとのスターターに置き換えます。

直す前(3.5.16):

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.5.16</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

直した後(4.1.1・classic で足場を作る):

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>4.1.1</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-classic</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test-classic</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

classic スターターは「すべてのモジュールを含むが、その先の推移的な依存は除く」構成です。公式も最終的には classic から離れることを勧めているので、次の手順まで進めて完了とします。

手順4:スターターを技術ごとに置き換える

使っている技術を1つずつ専用スターターに置き換え、最後に classic を外します。

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webmvc</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-flyway</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webmvc-test</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-flyway-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

Gradle(Kotlin DSL)では次のようになります。

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-webmvc")
    implementation("org.springframework.boot:spring-boot-starter-flyway")
    testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
    testImplementation("org.springframework.boot:spring-boot-starter-flyway-test")
}

置き換えの順番は、起動時に結果が目で見えるもの(Web → DB マイグレーション → データアクセス)から進めると、足りないスターターにすぐ気づけます。

手順5:Jackson 3に合わせる

Jackson 3 ではグループ ID とパッケージが com.fasterxml.jackson から tools.jackson に変わります。例外は jackson-annotations で、com.fasterxml.jackson.annotation のまま使えます。 つまり @JsonProperty や @JsonInclude の import は直さずに済みます。

直す前(3.5):

package com.example.demo;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Component;

@Component
public class JsonCustomizer implements Jackson2ObjectMapperBuilderCustomizer {

    @Override
    public void customize(Jackson2ObjectMapperBuilder builder) {
        // ここで builder を調整する
    }
}

直した後(4.1):

package com.example.demo;

import com.fasterxml.jackson.annotation.JsonInclude;   // annotation はそのまま
import tools.jackson.databind.json.JsonMapper;
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.stereotype.Component;

@Component
public class JsonCustomizer implements JsonMapperBuilderCustomizer {

    @Override
    public void customize(JsonMapper.Builder jsonMapperBuilder) {
        // ここで jsonMapperBuilder を調整する
    }
}

設定ファイルは、JSON の読み書きの機能(JsonReadFeature/JsonWriteFeature)を切り替えるキーに json. が入ります。

# 直す前(3.5)
spring.jackson.read.<機能名>=true
spring.jackson.write.<機能名>=true
spring.jackson.parser.<機能名>=true

# 直した後(4.1)
spring.jackson.json.read.<機能名>=true
spring.jackson.json.write.<機能名>=true
spring.jackson.json.read.<機能名>=true

spring.jackson.serialization.*(例:spring.jackson.serialization.indent_output=true)や spring.jackson.deserialization.*、spring.jackson.mapper.*、spring.jackson.default-property-inclusion は 4.1.1 のリファレンスに載っている名前です。

Jackson 3 への対応に時間が必要な場合のために、公式は2つの橋渡しを用意しています。

方法 設定 位置づけ
既定値を Jackson 2 に寄せる spring.jackson.use-jackson2-defaults=true Jackson 3 を使いつつ挙動を近づける
Jackson 2 の自動構成を使う spring-boot-jackson2 を追加(設定は spring.jackson2.*) 非推奨の形で提供される一時的な手段
モジュールの自動登録を止める spring.jackson.find-and-add-modules=false 4 で全モジュール登録になった点を戻す
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-jackson2</artifactId>
</dependency>

自動構成の Mapper を差し替えたい場合は、ObjectMapper ではなく JsonMapper(XML なら XmlMapper)の Bean を定義します。

手順6:テストのアノテーションを直す

4.0 では @SpringBootTest だけでは MockMvc も TestRestTemplate も用意されません。使うものをアノテーションで明示します。

直す前(3.5):

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class TaskControllerTest {

    @Autowired
    MockMvc mvc;

    @MockBean
    TaskService taskService;

    @Test
    void list() throws Exception {
        mvc.perform(get("/tasks")).andExpect(status().isOk());
    }
}

直した後(4.1):

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class TaskControllerTest {

    @Autowired
    MockMvc mvc;

    @MockitoBean
    TaskService taskService;

    @Test
    void list() throws Exception {
        mvc.perform(get("/tasks")).andExpect(status().isOk());
    }
}

変わるのは import 2行とアノテーション1つです。テストの種類ごとの対応は次のとおりです。

使っているもの 4 系で付けるもの 必要な依存
MockMvc @AutoConfigureMockMvc spring-boot-starter-webmvc-test
TestRestTemplate @AutoConfigureTestRestTemplate spring-boot-resttestclient と spring-boot-restclient
RestTestClient(新) @AutoConfigureRestTestClient spring-boot-resttestclient
@Mock/@Captor @ExtendWith(MockitoExtension.class) Mockito の JUnit 連携
HtmlUnit の無効化 @AutoConfigureMockMvc(htmlUnit = @HtmlUnit(webClient = false, webDriver = false)) 同上

TestRestTemplate のために spring-boot-restclient を足すと、RestClient.Builder の自動構成も有効になる点が公式リファレンスに注記されています。新しく書くテストは RestTestClient を選ぶと依存が1つで済みます。

複数のテストで同じモックを使う場合は、@MockitoBean(types = {TaskService.class, MemberService.class}) のようにテストクラス(または自作アノテーション)へまとめて書けます。

3系の書き方を探すスクリプト

上の対応表を、プロジェクトのフォルダに対して機械的に当てるスクリプトです。標準ライブラリだけで動き、.java/.kt/pom.xml/build.gradle/.properties/.yml を調べます。YAML は入れ子のキーを a.b.c の形に直してから照合します。

#!/usr/bin/env python3
"""Spring Boot 3 の書き方が残っている箇所を探す(標準ライブラリのみ)。
使い方: python3 boot4_scan.py <プロジェクトのフォルダ>
見つかれば終了コード 1、なければ 0。"""
import re
import sys
from pathlib import Path

# (分類, 正規表現, 直し方)
RULES = [
    ("Jackson", r"\bcom\.fasterxml\.jackson\.(?!annotation\b)[\w.]+", "tools.jackson.… に変更(annotation だけは元のまま)"),
    ("Jackson", r"\bJackson2ObjectMapperBuilderCustomizer\b", "JsonMapperBuilderCustomizer"),
    ("Jackson", r"\bJsonObjectSerializer\b", "ObjectValueSerializer"),
    ("Jackson", r"\bJsonValueDeserializer\b", "ObjectValueDeserializer"),
    ("Jackson", r"@JsonComponent\b", "@JacksonComponent"),
    ("Jackson", r"@JsonMixin\b", "@JacksonMixin"),
    ("テスト", r"@MockBean\b", "@MockitoBean"),
    ("テスト", r"@SpyBean\b", "@MockitoSpyBean"),
    ("テスト", r"\bMockitoTestExecutionListener\b", "MockitoExtension を使う"),
    ("テスト", r"\borg\.springframework\.boot\.test\.web\.client\.TestRestTemplate\b",
     "org.springframework.boot.resttestclient.TestRestTemplate"),
    ("テスト", r"\borg\.springframework\.boot\.test\.autoconfigure\.properties\.PropertyMapping\b",
     "org.springframework.boot.test.context.PropertyMapping"),
    ("null注釈", r"\borg\.springframework\.lang\.(Nullable|NonNull)\b", "org.jspecify.annotations の注釈へ"),
    ("コード", r"\bimport\s+org\.springframework\.boot\.(?!persistence\.autoconfigure\.)[\w.]*\.EntityScan\b",
     "org.springframework.boot.persistence.autoconfigure.EntityScan"),
    ("コード", r"\balwaysApplyingWhenNonNull\s*\(", "PropertyMapper の always() を検討"),
    ("コード", r"\bStreamBuilderFactoryBeanCustomizer\b", "StreamsBuilderFactoryBeanConfigurer"),
    ("コード", r"\bRabbitRetryTemplateCustomizer\b",
     "RabbitTemplateRetrySettingsCustomizer / RabbitListenerRetrySettingsCustomizer"),
    ("コード", r"\bRestClientBuilderCustomizer\b", "Rest5ClientBuilderCustomizer(Elasticsearch)"),
    ("スターター", r"spring-boot-starter-web(?![\w-])", "spring-boot-starter-webmvc"),
    ("スターター", r"spring-boot-starter-web-services(?![\w-])", "spring-boot-starter-webservices"),
    ("スターター", r"spring-boot-starter-aop(?![\w-])", "spring-boot-starter-aspectj"),
    ("スターター", r"spring-boot-starter-oauth2-(client|resource-server|authorization-server)(?![\w-])",
     "spring-boot-starter-security-oauth2-…"),
    ("スターター", r"spring-boot-starter-undertow(?![\w-])", "Tomcat か Jetty のスターターへ"),
    ("ビルド", r"\bhibernate-jpamodelgen\b", "hibernate-processor"),
    ("ビルド", r"loaderImplementation|LoaderImplementation\.CLASSIC", "設定ごと削除"),
    ("ビルド", r"jarmode=layertools", "jarmode=tools(4.1 で layertools は削除)"),
    ("設定", r"\bspring\.jackson\.(read|write)\.", "spring.jackson.json.read. / spring.jackson.json.write."),
    ("設定", r"\bspring\.jackson\.parser\.", "spring.jackson.json.read."),
    ("設定", r"\bspring\.session\.(redis|mongodb)\.", "spring.session.data.redis. / spring.session.data.mongodb."),
    ("設定", r"\bspring\.data\.mongodb\.(additional-hosts|authentication-database|database|host|password|port|"
            r"protocol|replica-set-name|representation\.uuid|ssl\.|uri|username)", "spring.mongodb.…"),
    ("設定", r"\bspring\.dao\.exceptiontranslation\.enabled\b", "spring.persistence.exceptiontranslation.enabled"),
    ("設定", r"\bmanagement\.(health|metrics)\.mongo\.", "management.health.mongodb. / management.metrics.mongodb."),
    ("設定", r"\bspring\.kafka\.retry\.topic\.backoff\.random\b", "spring.kafka.retry.topic.backoff.jitter"),
]
RULES = [(kind, re.compile(pattern), fix) for kind, pattern, fix in RULES]
TARGETS = {".java", ".kt", ".groovy", ".xml", ".gradle", ".kts", ".properties", ".yml", ".yaml", ".factories"}
SKIP_DIRS = {".git", "target", "build", "node_modules", ".gradle", ".idea"}


def flatten_yaml(lines):
    """インデントをたどって YAML のキーを a.b.c 形式に直す(リストや複数行の値は対象外の簡易版)。"""
    stack, out = [], []
    for number, raw in enumerate(lines, 1):
        match = re.match(r"^(\s*)([\w.-]+):", raw)
        if not match or raw.lstrip().startswith("#"):
            continue
        indent = len(match.group(1))
        while stack and stack[-1][0] >= indent:
            stack.pop()
        stack.append((indent, match.group(2)))
        out.append((number, ".".join(key for _, key in stack) + "."))
    return out


def scan(root):
    hits = []
    for path in sorted(root.rglob("*")):
        if not path.is_file() or path.suffix not in TARGETS or SKIP_DIRS & set(path.parts):
            continue
        lines = path.read_text(encoding="utf-8", errors="replace").splitlines()
        rows = flatten_yaml(lines) if path.suffix in {".yml", ".yaml"} else list(enumerate(lines, 1))
        seen = set()  # YAML は親キーと子キーで同じ指摘が重なるので 1 回にまとめる
        for number, text in rows:
            for kind, regex, fix in RULES:
                found = regex.search(text)
                if found and (path, found.group(0)) not in seen:
                    seen.add((path, found.group(0)) if path.suffix in {".yml", ".yaml"} else (path, number, kind, fix))
                    hits.append((kind, path.relative_to(root), number, found.group(0), fix))
    # ファイルをまたいで判断するもの:Flyway・Liquibase を使っているのに専用スターターが無い
    build_text = "\n".join(p.read_text(encoding="utf-8", errors="replace")
                           for p in root.rglob("*") if p.name in {"pom.xml", "build.gradle", "build.gradle.kts"})
    for lib, starter in (("flyway-core", "spring-boot-starter-flyway"), ("liquibase-core", "spring-boot-starter-liquibase")):
        if lib in build_text and starter not in build_text:
            hits.append(("スターター", Path("(ビルド定義)"), 0, lib, starter + " を追加"))
    return hits


def main():
    root = Path(sys.argv[1] if len(sys.argv) > 1 else ".")
    hits = scan(root)
    for kind, path, number, found, fix in hits:
        print(f"[{kind}] {path}:{number}  {found}  ->  {fix}")
    counts = {}
    for kind, *_ in hits:
        counts[kind] = counts.get(kind, 0) + 1
    print("-" * 60)
    print("合計", len(hits), "件", " ".join(f"{k}={v}" for k, v in counts.items()))
    sys.exit(1 if hits else 0)


if __name__ == "__main__":
    main()

3.5 の書き方が残っている小さなサンプル(pom.xml、設定クラス、application.yml、テスト各1ファイル)に対して実行した結果です。

$ python3 tools/boot4_scan.py sample
[スターター] pom.xml:10  spring-boot-starter-web  ->  spring-boot-starter-webmvc
[スターター] pom.xml:14  spring-boot-starter-aop  ->  spring-boot-starter-aspectj
[Jackson] src/main/java/com/example/demo/JsonConfig.java:4  com.fasterxml.jackson.databind.SerializationFeature  ->  tools.jackson.… に変更(annotation だけは元のまま)
[Jackson] src/main/java/com/example/demo/JsonConfig.java:5  Jackson2ObjectMapperBuilderCustomizer  ->  JsonMapperBuilderCustomizer
[null注釈] src/main/java/com/example/demo/JsonConfig.java:8  org.springframework.lang.Nullable  ->  org.jspecify.annotations の注釈へ
[Jackson] src/main/java/com/example/demo/JsonConfig.java:13  Jackson2ObjectMapperBuilderCustomizer  ->  JsonMapperBuilderCustomizer
[設定] src/main/resources/application.yml:3  spring.jackson.write.  ->  spring.jackson.json.read. / spring.jackson.json.write.
[設定] src/main/resources/application.yml:6  spring.session.redis.  ->  spring.session.data.redis. / spring.session.data.mongodb.
[設定] src/main/resources/application.yml:10  spring.dao.exceptiontranslation.enabled  ->  spring.persistence.exceptiontranslation.enabled
[テスト] src/test/java/com/example/demo/TaskControllerTest.java:5  org.springframework.boot.test.web.client.TestRestTemplate  ->  org.springframework.boot.resttestclient.TestRestTemplate
[テスト] src/test/java/com/example/demo/TaskControllerTest.java:9  @MockBean  ->  @MockitoBean
[スターター] (ビルド定義):0  flyway-core  ->  spring-boot-starter-flyway を追加
------------------------------------------------------------
合計 12 件 スターター=3 Jackson=3 null注釈=1 設定=3 テスト=2
$ echo $?
1

pom.xml に flyway-core があるのに spring-boot-starter-flyway が無い、というファイルをまたいだ指摘も最後に出ています。終了コードは見つかれば 1、無ければ 0 なので、CI に入れておくと、移行後に 3 系の書き方が戻ってきたときに検知できます。

スクリプトを置かずに手早く見たいときは、grep でも主なものは拾えます。同じサンプルでの実行結果です。

$ grep -rnE 'com\.fasterxml\.jackson\.(databind|core|datatype|dataformat|module)|@MockBean|@SpyBean|spring-boot-starter-(web|aop)<' sample
sample/src/test/java/com/example/demo/TaskControllerTest.java:9:    @MockBean
sample/src/main/java/com/example/demo/JsonConfig.java:4:import com.fasterxml.jackson.databind.SerializationFeature;
sample/pom.xml:10:      <artifactId>spring-boot-starter-web</artifactId>
sample/pom.xml:14:      <artifactId>spring-boot-starter-aop</artifactId>

コピペ用の移行チェックリスト

Issue やプルリクエストの説明にそのまま貼れる形です。該当しない行は消して使ってください。

# Spring Boot 4 移行チェックリスト

## 0. 準備
- [ ] 現在の版と行き先の版を決めた(例:3.5.x → 4.1.1)
- [ ] Java 17 以上で動いている(jOOQ を使うなら 21 以上)
- [ ] 依存ライブラリ(Spring Cloud など)の 4 系対応版を確認した
- [ ] 移行用のブランチを切り、CI が通る状態から始めた

## 1. 3.5 系の最新版へ
- [ ] spring-boot の版を 3.5 系の最新に上げた
- [ ] ビルドと全テストが通る

## 2. 非推奨の解消
- [ ] -Xlint:deprecation を有効にして警告を一覧にした
- [ ] 非推奨のクラス・メソッド・プロパティを置き換えた
- [ ] spring-boot-properties-migrator を一時的に追加した

## 3. classic スターターで 4 へ
- [ ] spring-boot の版を 4.1.1 にした
- [ ] spring-boot-starter → spring-boot-starter-classic
- [ ] spring-boot-starter-test → spring-boot-starter-test-classic
- [ ] Undertow を使っていれば Tomcat か Jetty に替えた
- [ ] loaderImplementation(CLASSIC)の設定を削除した
- [ ] コンパイルが通る

## 4. スターターを個別に置き換え
- [ ] spring-boot-starter-web → spring-boot-starter-webmvc
- [ ] spring-boot-starter-aop → spring-boot-starter-aspectj
- [ ] oauth2 系 → spring-boot-starter-security-oauth2-…
- [ ] Flyway/Liquibase 用のスターターを追加した
- [ ] Spring Batch のメタデータ保存先を確認した(DB なら -batch-jdbc)
- [ ] 技術ごとの -test スターターを追加した
- [ ] classic スターターを外しても起動する

## 5. Jackson 3
- [ ] import を com.fasterxml.jackson → tools.jackson に変更(annotation は除く)
- [ ] Jackson2ObjectMapperBuilderCustomizer → JsonMapperBuilderCustomizer
- [ ] @JsonComponent/@JsonMixin → @JacksonComponent/@JacksonMixin
- [ ] spring.jackson.read/write/parser → spring.jackson.json.read/write
- [ ] JSON の入出力(日付・null・数値)を確かめるテストが通る
- [ ] 橋渡し(use-jackson2-defaults/spring-boot-jackson2)を使った場合は外す予定を決めた

## 6. テスト
- [ ] @MockBean/@SpyBean → @MockitoBean/@MockitoSpyBean
- [ ] MockMvc を使うテストに @AutoConfigureMockMvc を付けた
- [ ] TestRestTemplate を使うテストに @AutoConfigureTestRestTemplate を付けた
- [ ] @Mock/@Captor のテストに MockitoExtension を付けた
- [ ] 全テストが通る

## 7. 黙って変わる点の確認
- [ ] /actuator/health に liveness/readiness が出てよいか
- [ ] ログファイルの文字コード(UTF-8)
- [ ] 設定キーの名前変更(Session・MongoDB・Kafka・persistence)
- [ ] DevTools のライブリロードの要否
- [ ] Maven の optional 依存が JAR に必要か
- [ ] Dockerfile の jarmode=layertools → jarmode=tools

## 8. 仕上げ
- [ ] spring-boot-properties-migrator を外した
- [ ] 3 系の書き方の検出スクリプトが 0 件
- [ ] 関連ライブラリのリリースノートを確認した(Framework 7.0/Security 7.0/Data 2025.1 など)

よくあるつまずきと直し方

症状 原因 直し方
com.fasterxml.jackson.databind が見つからない Jackson 3 でパッケージが変わった tools.jackson.databind に直す
@MockBean が見つからない 4.0 で削除 @MockitoBean に直す
MockMvc を注入できない @SpringBootTest が自動構成しなくなった @AutoConfigureMockMvc を付ける
マイグレーションが走らずテーブルが無い Flyway 用スターターが無い spring-boot-starter-flyway を足す
バッチの履歴が DB に残らない spring-boot-starter-batch がメモリ動作になった spring-boot-starter-batch-jdbc に替える
設定を書いたのに効かない キーの名前が変わった properties-migrator で診断し、対応表で直す
@Nullable を付けた Actuator の引数が必須扱いになる org.springframework.lang.Nullable が対象外 org.jspecify.annotations.Nullable に直す

よくある質問

Q. 3.5 を飛ばして、3.4 以前から直接 4 に上げられますか? A. 公式移行ガイドは、先に 3.5 系の最新版へ上げて非推奨の呼び出しを見直すことを最初の手順にしています。3 系で非推奨だったものは 4.0 で削除されているため、3.5 で警告を消しておくほうが、4 に上げたあとのエラーが少なく済みます。

Q. classic スターターはいつまで使えますか? A. 公式は「早く動かしたいときの手段」と位置づけ、最終的には classic から離れることを勧めています。期限は移行ガイドに書かれていないので、技術ごとのスターターへの置き換えまでを移行の完了条件にしておくと安心です。

Q. Jackson 2 のまま 4 に上げることはできますか? A. spring-boot-jackson2 モジュールを追加すると Jackson 2 の ObjectMapper が自動構成されます。ただし非推奨の形での提供で、将来のリリースで削除される予定と明記されています。Jackson 3 を使いつつ既定値だけ 2 に近づける spring.jackson.use-jackson2-defaults=true もあります。

Q. 4.0 と 4.1 のどちらを目指すのがよいですか? A. 4.0系の OSS サポートは 2026年12月31日までなので、これから上げるなら 4.1系(2027年7月31日まで)が候補になります。4.0 から 4.1 への変更は、4.0 で非推奨だったものの削除と layertools の削除などに限られます。

まとめ

  • 移行は6段階:3.5 最新化 → 非推奨の解消 → classic スターターで 4 へ → スターター個別化 → Jackson 3 → テスト。
  • 行き先は 4.1系:3.5系の OSS サポートは 2026-06-30 に終了、4.0系は 2026-12-31 まで、4.1系は 2027-07-31 まで。
  • コンパイルで分かる変更(パッケージ名、@MockBean、Undertow)は、エラーを順に直せば進む。
  • 黙って変わる変更(Flyway/Liquibase のスターター、Spring Batch の保存先、設定キーの名前変更、liveness/readiness)は、先に確認用のテストを用意する。
  • Jackson 3 は tools.jackson。jackson-annotations だけは com.fasterxml.jackson.annotation のまま。
  • テストは明示する:@AutoConfigureMockMvc、@AutoConfigureTestRestTemplate、@MockitoBean。
  • 検出スクリプトとチェックリストを CI とプルリクエストに置くと、直し漏れを減らせる。

参考・出典

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

  • Spring Boot 4.0 Migration Guide: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide
  • Spring Boot 4.1 Release Notes: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.1-Release-Notes
  • Spring Boot プロジェクトページ(現行 4.1.1): https://spring.io/projects/spring-boot
  • 世代別サポート期間: https://api.spring.io/projects/spring-boot/generations
  • Supported Versions(サポート方針): https://github.com/spring-projects/spring-boot/wiki/Supported-Versions
  • MockBean API(3.5.16、非推奨の注記): https://docs.spring.io/spring-boot/3.5/api/java/org/springframework/boot/test/mock/mockito/MockBean.html
  • Testing Spring Boot Applications(4.1.1): https://docs.spring.io/spring-boot/reference/testing/spring-boot-applications.html
  • JSON(4.1.1): https://docs.spring.io/spring-boot/reference/features/json.html
  • Customize the Jackson JsonMapper(4.1.1): https://docs.spring.io/spring-boot/how-to/spring-mvc.html
  • JsonMapperBuilderCustomizer API(4.1.1): https://docs.spring.io/spring-boot/4.1.1/api/java/org/springframework/boot/jackson/autoconfigure/JsonMapperBuilderCustomizer.html

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

(記載例)出典:株式会社RJC「Spring Boot 4移行の手順|3から4の変更点一覧とチェックリスト」

株式会社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で一緒に開発しながら、 成長を楽しみませんか?