Software

Spring Boot 4 and Jackson 3: the silent catch problem

By · Fri Aug 21 2026 · 6 min read · 0 views

View as a Web Story

Software#migration#spring boot#java#jackson#backend

Spring Boot 4 upgrade path and the Jackson 3 exception change

Spring Boot 4 and Jackson 3: the silent catch problem

Most of the Spring Boot 4 migration announces itself. Packages move, classes get renamed, and the compiler tells you. One change does not, and it is the one worth reading first.

In Jackson 2, JsonProcessingException extended IOException. In Jackson 3, JacksonException extends RuntimeException. So a catch (IOException e) block that used to absorb JSON parse failures stops catching them. Nothing fails to compile. Nothing warns. The error just travels somewhere else, usually to a generic 500 handler.

Why this migration is urgent now

Spring Boot is the application framework most Java services are built on, and its open-source support windows are short. Spring Boot 3.5 lost open-source support in June 2026. The final free release was 3.5.16 on June 25, 2026, and every 3.x branch is now out of open-source support. Paid enterprise support for 3.5 runs to June 2032.

That matters more than any feature list. Once a branch closes, new CVEs in that line get no community patch on Maven Central. Teams that stayed on 3.5 for stability now carry unpatched risk instead. That is the opposite of what the choice was meant to buy.

So the question is no longer whether to move to Spring Boot 4. It is what order to do it in.

What actually changed with Jackson

Jackson is the JSON serialization library Spring Boot uses by default. Spring Boot 4 prefers Jackson 3, and the official migration guide lists the moves.

Change Jackson 2 Jackson 3
Group and package com.fasterxml.jackson tools.jackson
Base exception JsonProcessingException extends IOException JacksonException extends RuntimeException
Serializer base JsonObjectSerializer ObjectValueSerializer
Builder customizer Jackson2ObjectMapperBuilderCustomizer JsonMapperBuilderCustomizer
Component annotation @JsonComponent @JacksonComponent
Read and write properties spring.jackson.read.* spring.jackson.json.read.*

One carve-out is worth memorising. jackson-annotations stays under com.fasterxml.jackson.core, per the same guide. That single exception breaks a lot of blind find-and-replace runs.

The catch block that stops working

Here is the pattern that breaks. It is common in file and stream handling, where JSON parsing sits inside code that already deals with IOException.

try {
    Report report = objectMapper.readValue(inputStream, Report.class);
    return ResponseEntity.ok(report);
} catch (IOException e) {
    // Under Jackson 2 this caught malformed JSON too.
    return ResponseEntity.badRequest().body("Invalid report payload");
}

Under Jackson 2 that returned a clean 400 for malformed JSON. Under Jackson 3 the parse failure is a RuntimeException. It goes straight past this block. The user gets a 500. Your handler still looks correct in code review.

Find the affected sites before you upgrade, not after:

Advertisement

rg -n "catch\s*\(\s*IOException" --type java

Then check each hit for a Jackson call inside the try. For example, a controller reading a multipart upload usually has one. A Kafka consumer that parses payloads by hand almost always does.

The fix is explicit rather than clever:

} catch (JacksonException e) {
    return ResponseEntity.badRequest().body("Invalid report payload");
} catch (IOException e) {
    return ResponseEntity.status(500).body("Read failed");
}

What else changes behaviour without failing the build

Serialization output shifts too. That lands in your API contract, not your compiler. Reports from teams already through the Spring Boot 4 migration rank unexpected output second only to package errors. Custom date formats, null handling and BigDecimal output all behave differently under Jackson 3 defaults.

Three checks catch most of it.

  1. Snapshot your JSON before the upgrade. Record the exact response body for your ten busiest endpoints. Diff after. This is the whole methodology, and it takes an hour.
  2. Look hard at BigDecimal. Money fields are where a changed number format becomes a customer-visible defect, such as a price rendering as 19.90 in one release and 19.9 in the next.
  3. Re-test null handling. Clients that treat a missing field differently from a null field will notice before you do.

Can you stay on Jackson 2 for now?

Yes, and it is a fair staging step. Spring Boot 4 ships a deprecated spring-boot-jackson2 module. It also adds a spring.jackson.use-jackson2-defaults property, which aligns the auto-configured mapper with Jackson 2 behaviour. Both are documented in the Spring Boot 4.0 migration guide.

Use it to split one risky release into two boring ones. Move to Spring Boot 4 with Jackson 2 defaults first, confirm the service is stable, then migrate the JSON layer as its own change.

Two caveats apply. The module is deprecated on arrival, so the bridge has a posted expiry. And Spring's Jackson 3 announcement notes real limits when other libraries expect one version. Mixing versions is a scheduling tool, not a destination.

Should you upgrade now, wait, or split it?

Split it, and start now. The end-of-life date has already passed, so waiting is no longer a low-risk option.

A workable order for a service in production looks like this.

  1. Upgrade to Spring Boot 4 with Jackson 2 defaults. Set spring.jackson.use-jackson2-defaults to true and ship. Nothing about your JSON should change.
  2. Fix the exception handling. Add JacksonException catches ahead of IOException catches, before Jackson 3 defaults are live.
  3. Switch to Jackson 3 defaults. Diff your snapshotted JSON responses. Fix the format differences you find.
  4. Remove the bridge. Drop spring-boot-jackson2 once nothing depends on it, because it will not be supported indefinitely.

Teams following the published Spring Boot 3 to 4 upgrade playbook run the same order. The reason is simple. Each step has one failure mode, so a break points at one change.

What this costs, honestly

For a small service with clean JSON handling, this is a day of work. For a large codebase with hand-rolled serializers, custom @JsonComponent classes and Kafka parsing, budget a sprint. Expect the exception-handling audit to be the slowest part.

The shape will feel familiar to anyone who has done a Pydantic AI v2 migration: the change that throws no error is the one that costs the weekend. It is also why a TypeScript 7 upgrade, where the compiler shouts at you, is the easier kind of migration to plan.

The cost of skipping it is a closed support branch. That is what should set the schedule. The migration effort is finite. The next unpatched CVE is not.

Advertisement

FAQ

Does Jackson 3 break existing catch blocks in Spring Boot 4?

Yes, silently. Jackson 2's `JsonProcessingException` extended `IOException`, while Jackson 3's `JacksonException` extends `RuntimeException`. Existing `catch (IOException e)` blocks still compile, but no longer catch JSON parse failures, so malformed input reaches your generic error handler instead.

What package do Jackson 3 classes use in Spring Boot 4?

Jackson 3 moves from `com.fasterxml.jackson` to `tools.jackson`. The exception is `jackson-annotations`, which stays under `com.fasterxml.jackson.core`. Custom serializers, deserializers and any code importing Jackson internals all need the new import paths.

Can I use Jackson 2 with Spring Boot 4?

Yes. Spring Boot 4 provides a deprecated `spring-boot-jackson2` module and the `spring.jackson.use-jackson2-defaults` property, which aligns the auto-configured mapper with Jackson 2 behaviour. Treat it as a temporary bridge, since the module is deprecated from the start.

When did Spring Boot 3.5 reach end of life?

Spring Boot 3.5 lost open-source support in June 2026, and the final free release, 3.5.16, shipped on June 25, 2026. Every Spring Boot 3.x branch is now outside open-source support, so community security patches for those lines no longer arrive on Maven Central. Commercial enterprise support for 3.5 continues until June 2032.

Comments

Loading…

Sign in to join the conversation.

Related posts

Next.js version branches and the August 26, 2026 security patch

Next.js security release lands August 26. Prep now

Vercel has told everyone that a critical bug exists in Next.js, and has not yet said what it is. The Next.js security release lands on August 26, 2026. It fixes one critical-severity vulnerability,

Fri Aug 21 2026 · 6 min read · 0 views

Software

We use cookies for ads and analytics.what this means.