Spring Boot を 3 系から 4 に上げた直後のビルドが、次のコンパイルエラーで止まります。
Main.java:1: error: package com.fasterxml.jackson.databind does not exist
import com.fasterxml.jackson.databind.ObjectMapper;
^
Main.java:5: error: cannot find symbol
ObjectMapper mapper = new ObjectMapper();
^
symbol: class ObjectMapper
location: class Main
依存の宣言も import も Boot 3 のときのままで、このエラーだけが新しく出ます。Boot 4 が管理する Jackson 3 は、
Maven 座標と Java package の両方を com.fasterxml.jackson から tools.jackson へ改名しています——
ただし全部ではありません。annotations だけが旧名に残るため、同じソースの import が一部だけ通ります。
直し方の要点を先に
databind の import を tools.jackson へ書き換えます。com.fasterxml.jackson.annotation の import はそのまま残します。
import com.fasterxml.jackson.annotation.JsonProperty; // 変えない(Jackson 3 でもこの package のまま)
import tools.jackson.databind.ObjectMapper; // 旧: com.fasterxml.jackson.databind.ObjectMapper
public class Employee {
@JsonProperty("employee_id")
public int id;
}
引数なしの new ObjectMapper() は Jackson 3 でも動きます(3.0.2 でコンパイル・実行とも実測済み)。ただし
Jackson 3 の ObjectMapper は生成後に設定を変えられません——configure(...) や setSerializationInclusion(...)
などの設定メソッドは 3.0 で削除されており、呼んでいる行は cannot find symbol でコンパイルが止まります。
設定を持つ mapper は JsonMapper.builder()....build() で組みます(上流の移行ガイドの推奨もこちら。
組み方の実例は姉妹記事にあります)。依存の追加は不要です——spring-boot-starter-json が Jackson 3 の
databind を運んでいます(検証もこの starter だけの構成で行いました)。
なぜ Spring Boot 4 で出るのか:Jackson 3 の改名は annotations を除く部分改名
Spring Boot 4.0.0 の spring-boot-starter-json が classpath に置く Jackson は、mvn dependency:tree の実測でこうなっています。
| モジュール | Boot 3.4.1(Jackson 2・実測) | Boot 4.0.0(Jackson 3・実測) |
|---|---|---|
| databind | com.fasterxml.jackson.core:jackson-databind(2.18.2) | tools.jackson.core:jackson-databind(3.0.2) |
| core | com.fasterxml.jackson.core:jackson-core | tools.jackson.core:jackson-core(3.0.2) |
| annotations | com.fasterxml.jackson.core:jackson-annotations | com.fasterxml.jackson.core:jackson-annotations(座標・package とも旧名のまま。版は 2.20) |
(版番号は実測した2点のもの。Boot 3 系でも databind の座標と package は同じですが、管理される版は Boot の版ごとに違います。)
classpath に com.fasterxml.jackson.databind package を提供する jar が居なくなったので、旧 import のコンパイルが
does not exist で止まります。一方 annotations は座標も package も変わらず classpath に残るので、同じ Boot 4.0.0 の
classpath で次の2つが同時に成り立ちます(どちらも実測)。
import com.fasterxml.jackson.databind.ObjectMapper;→ コンパイルエラーimport com.fasterxml.jackson.annotation.JsonProperty;→ コンパイル成功
@JsonProperty や @JsonIgnore の import が通り続けるため、エラーになるのは databind/core を直接触る箇所だけです。
annotations を旧名に残すのは Jackson 3 の設計判断です——2 系と 3 系のどちらからも同じ annotation を読めるように
する互換措置で、移行中にドメインクラスの annotation を付け替えずに済みます(Jackson の移行ガイドが明記しています)。
書き換えの判断基準は Java annotation かどうかではなく、module 単位で決まります:旧名に残るのは
jackson-annotations module(com.fasterxml.jackson.annotation.*)だけです。同じ annotation でも databind に属する
@JsonSerialize / @JsonDeserialize(com.fasterxml.jackson.databind.annotation.*)は
tools.jackson.databind.annotation.* へ動きます(旧 import はコンパイルエラー・新 import は成功、を実測)。
旧 Jackson 2 を classpath に足すとどうなるか
依存に com.fasterxml.jackson.core:jackson-databind:2.18.2 を明示追加する経路も実測しました。旧 import のままの
コードがコンパイル・実行とも通ります(classpath には jackson-databind-3.0.2.jar と jackson-databind-2.18.2.jar が
両方載り、tools.jackson と com.fasterxml.jackson は別 package なので FQCN は衝突しません)。なお明示追加した
databind は 2.18.2 でも、Jackson 2 側の core と annotations は Boot 4 の依存管理が 2.20 系(2.20.1/2.20)を
選びます——Jackson 2 側の内部でも版がズレて組まれる、ということです。
実測が示すのはそこまでです。この構成はアプリの中で Jackson 2 と Jackson 3 の2世代が並走することを意味し、
自分のコードがどちらの ObjectMapper を使うかと、Boot 4 側の JSON 変換(既定は Jackson 3。Jackson 2 の
自動構成も非推奨のまま同梱されています)がどちらを使うかは別々に決まります。単純なプローブが通ることは、
混在した実アプリ全体の互換を示しません。Boot 4 での段階移行には公式の経路もあります——spring-boot-jackson2
モジュールと spring.jackson2.* 設定が、非推奨(将来削除予定)の一時経路として Boot 4.0 のリリースノートに
明記されています。どの経路を取るにせよ、進む先は import の書き換えです。
切り分け(うまくいかないとき)
- コンパイルは通ったのに、実行時に
Cannot mapnullinto typeint“ が出るようになった:Jackson 3 は 名前空間だけでなく既定の挙動も変えています(JSON の null をプリミティブに入れる変換が既定で例外に)。 Cannot mapnullinto typeintの直し方 を参照してください。 - エラーが
package javax.persistence does not existなどjavax.*系で出ている:それは Boot 4 ではなく Boot 2→3(Jakarta EE 9 の名前空間改名)の境界です。形は同じ「版を上げたら package が消える」ですが、 改名したコンポーネントが違います。 package javax.persistence does not exist の直し方 を参照してください。 jakarta.mailのように、依存の版だけで package が変わった経験がある:あちらは「座標が先に改名され、 中身が後から追いつく」罠でした。Jackson 3 は逆に「座標と package は同時に変わるが、annotations という module だけが旧名に残る」形です。どちらも改名が一斉でないことが引っかかりの原因ですが、確認する軸が 違います(あちらは版、こちらは module)。 package javax.mail does not exist の直し方 を参照してください。- 自分のコードは直したのに、依存ライブラリの中で
com.fasterxml.jackson.databind系のNoClassDefFoundErrorが 実行時に出る:そのライブラリが Jackson 2 の databind を前提にしています。ライブラリ側の Jackson 3 対応版を 探すか、上の「旧 Jackson 2 を classpath に足す」の限定を踏まえて2世代並走を検討することになります。
検証環境
maven:3.9-eclipse-temurin-21(digest 固定)の中で Maven を実行(依存の取得にのみネットワークを使用)- 依存は
spring-boot-starter-jsonのみ(Spring MVC もサーバも使わない最小構成) - 再現:Spring Boot 4.0.0 の classpath で
import com.fasterxml.jackson.databind.ObjectMapper;をコンパイルするとpackage com.fasterxml.jackson.databind does not existで終了コード 1 - 修正:databind の import を
tools.jackson.databind.ObjectMapperに書き換え(@JsonPropertyの import はcom.fasterxml.jackson.annotationのまま)、コンパイル・実行とも終了コード 0・シグネチャ消滅
再現から修正までは errfix の検証ハーネスが機械的に確認しています。「annotations の import は同じ classpath で通る」
「new ObjectMapper() が Jackson 3.0.2 で動く」「旧 Jackson 2 databind の明示追加で旧 import が動く」の3点は
個別に実測しました(各結果はケースの verification/probes.txt に記録)。座標と版の対応は mvn dependency:tree で
確認しています。