跪拜 Guibai
← Back to the summary

Jackson 3 Breaks Everything: New Package, Immutable Mapper, and a Mandatory JDK 17 Floor

Foreword

Recently, while upgrading to Spring Boot 4, I discovered a very common phenomenon — most people are caught off guard by the 'invisible bomb' that is Jackson 3.

After the project started, the console reported a bunch of inexplicable errors.

Looking over them, it turned out not to be a problem with the business code, but breaking changes brought by the Jackson upgrade.

"Isn't Jackson just a JSON serialization tool? What's the big deal about upgrading?"

If you think that way, it means you haven't truly understood Jackson's position in the Java ecosystem.

Jackson is not just 'a JSON library'; it is the de facto standard JSON implementation in the Java ecosystem.

Spring Boot, microservice communication, Redis serialization, log parsing — almost everywhere JSON is involved, Jackson is used under the hood.

Upgrading from Jackson 2.x to 3.x is not a 'seamless upgrade'.

It is Jackson's first major version number change in 8 years.

From its inception at the end of 2017 to the official GA release on October 3, 2025, it went through 10 RC versions.

In this article today, I will break down Jackson 3's new features and migration points for you from start to finish.

I hope it will be helpful to you.

For more project practices, visit my technical website: susan.net.cn/project

1. What Exactly Is 'New' About Jackson 3?

Before discussing specific features, let's establish an overall understanding.

Jackson 3 is a refactoring-oriented evolution with a very clear set of values.

If Jackson 2 leaned more towards 'compatibility with all historical baggage', then Jackson 3's goal is very clear — security, type clarity, and modern Java orientation.

image.png

This diagram basically summarizes the core changes of Jackson 3.

Below, I will break them down for you one by one.

2. JDK Baseline Upgraded to Java 17

This is the most fundamental change in Jackson 3. Jackson 3.x requires JDK 17+.

Jackson 2.x minimally supports JDK 8.

From JDK 8 to JDK 17, 9 years and 4 LTS versions have passed.

This upgrade means Jackson 3 can fully utilize the new features of Java 17 — Records, Sealed Classes, Pattern Matching, etc.

Impact on you: If your project is still on JDK 8 or 11 and you want to use Jackson 3, you must upgrade the JDK first. The good news is that Spring Boot 3.x already requires JDK 17, so most new projects already meet this condition.

3. Comprehensive Changes to Package Names and groupId

This is the most 'conspicuous' change, and also the first compilation error you will encounter when upgrading.

Comparison Item Jackson 2.x Jackson 3.x
Maven groupId com.fasterxml.jackson tools.jackson
Java Package Name com.fasterxml.jackson.xxx tools.jackson.xxx
Annotation Package Name com.fasterxml.jackson.annotation Remains Unchanged
// Jackson 2.x style
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonParser;

// Jackson 3.x style
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.core.JsonParser;

Why does the annotation package name remain unchanged?

This is a very clever design. The Jackson team left the annotation library (jackson-annotations) under the original groupId and package name, and only moved the core processing logic to tools.jackson. Jackson 3.0 uses jackson-annotations version 2.20.

This means: Jackson 2 and Jackson 3 can coexist in the same project. Your core application can use Jackson 3, while old third-party dependency libraries can still use Jackson 2, without interfering with each other.

But note one exception: Annotations inside jackson-databind (like @JsonSerialize, @JsonDeserialize) will move to the new package tools.jackson.databind.annotation.

4. ObjectMapper Becomes the Immutable JsonMapper

This is the change with the widest impact in Jackson 3.

In Jackson 2.x, ObjectMapper is mutable. You could write:

// Jackson 2.x - Mutable configuration
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);      // Can be changed anytime
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// State can be modified at any time

This design can cause problems in multi-threaded environments — one thread modifies the configuration while another is using it, leading to unpredictable behavior.

Jackson 3.x mandates the Builder pattern, and the configuration is locked once construction is complete:

// Jackson 3.x - Immutable Builder pattern
JsonMapper mapper = JsonMapper.builder()
    .enable(SerializationFeature.INDENT_OUTPUT)
    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
    .build();  // Configuration is locked once build() is called

image.png

Must use format-aligned subclasses: In Jackson 3, you must use an ObjectMapper subclass that matches the data format:

// Jackson 2.x - Can mix
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());

// Jackson 3.x - Must use the corresponding Mapper
JsonMapper jsonMapper = JsonMapper.builder().build();   // JSON
YAMLMapper yamlMapper = YAMLMapper.builder().build();   // YAML
XmlMapper xmlMapper = XmlMapper.builder().build();      // XML

Prohibited: The new ObjectMapper(new YAMLFactory()) style.

5. Exception System Refactored

Jackson 2.x uses Checked ExceptionsJsonProcessingException is a subclass of Exception, requiring explicit try-catch or throws.

Jackson 3.x switches to Unchecked Exceptions:

Jackson 2.x Jackson 3.x
JsonProcessingException JacksonException (Base class)
JsonParseException StreamReadException
JsonEOFException UnexpectedEndOfInputException
// Jackson 2.x - Must handle checked exception
try {
    User user = mapper.readValue(json, User.class);
} catch (JsonProcessingException e) {
    // Must handle
}

// Jackson 3.x - Unchecked exception, can choose not to catch
User user = mapper.readValue(json, User.class);
// If an error occurs, throws JacksonException (runtime exception)

This change makes Jackson's API more aligned with modern Java programming habits, consistent with mainstream frameworks like Spring and Lombok.

6. Comprehensive Adjustment of Default Configuration

Jackson 3 has changed a large number of default configurations.

I'll pick a few that are most likely to 'blow up on you'.

6.1 Date Serialization: From Timestamps to ISO-8601 Strings

This is one of the most easily overlooked and most impactful changes.

// Jackson 2.x Default: 2026-07-20 12:00:00 → 1721462400000 (Timestamp)

// Jackson 3.x Default: 2026-07-20 12:00:00 → "2026-07-20T12:00:00Z" (ISO-8601 String)

If your frontend code depends on the timestamp format, the data format returned by the API will change after the upgrade. The good news is, it can be explicitly configured back:

JsonMapper mapper = JsonMapper.builder()
    .enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)  // Change back to timestamps
    .build();

6.2 Primitive Type Null Values: From Lenient to Strict

Jackson 3.x changes the default value of FAIL_ON_NULL_FOR_PRIMITIVES from false to true.

// Suppose you have this DTO
public class User {
    private int age;  // Primitive type int
}

// Jackson 2.x: When age is null in JSON, defaults to 0
// Jackson 3.x: When age is null in JSON, throws JsonMappingException

This change will cause many codes that 'used to run' to suddenly error. Solution: either change int to Integer, or explicitly disable this feature.

6.3 Month Counting: From 0-based to 1-based

In Java's java.util.Date, months start from 0 (0=January). Jackson 3.x changes the default value of DateTimeFeature.ONE_BASED_MONTHS from false to true.

This means the handling of months during serialization/deserialization has changed. If your code relies on the '0=January' logic, pay special attention after upgrading.

7. Performance and Memory Optimization

Jackson 3 is not just about 'changing APIs'; it has also done a lot of optimization in performance and memory.

7.1 BeanDescription Lazy Loading Optimization

Jackson 3.0 introduces the Supplier pattern to implement lazy loading for the BeanDescription implementation. For simple types or scenarios not requiring a full BeanDescription, unnecessary parsing overhead is avoided. This reduces the creation of temporary objects and GC pressure.

7.2 RecyclerPool Lazy Initialization

Jackson Core 3.0 optimizes the initialization strategy for RecyclerPool. In applications with high-frequency Jackson usage, this can significantly improve memory usage efficiency.

7.3 Field Name Deduplication Disabled

Jackson 3.0 changes the default value of TokenStreamFactory.Feature.INTERN_FIELD_NAMES to false. This means JSON field names are no longer automatically cached in the string constant pool, reducing memory footprint.

8. Module Integration: Three Fewer Dependencies

In Jackson 2.x, to support Java 8's new features, you needed to introduce three additional modules:

<!-- Jackson 2.x requires additional imports -->
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

In Jackson 3.x, these three modules have been integrated into jackson-databind. No separate introduction is needed.

9. Breaking Changes Quick Reference

I've compiled a quick reference table of the changes in Jackson 3 most likely to cause your code to error:

Change Type Jackson 2.x Jackson 3.x Impact
Base Exception JsonProcessingException (Checked) JacksonException (Unchecked) try-catch needs change
ObjectMapper Mutable, just new it Immutable, must use Builder All creation code needs change
Package Name com.fasterxml.jackson tools.jackson All imports need change
groupId com.fasterxml.jackson.core tools.jackson.core pom.xml needs change
Date Default Timestamp ISO-8601 String API return format changes
Primitive Type null Allowed (assigns default value) Throws exception May cause new errors
ObjectCodec Exists Removed Casting code errors
JsonGenerator.writeObject() Exists Changed to writePOJO() Method name needs change
JsonParser.getCurrentLocation() Exists Changed to currentLocation() Method name needs change

10. Advantages, Disadvantages, and Applicable Scenarios

Advantages of Jackson 3

1. Thread Safety Guaranteed JsonMapper is immutable; configuration is locked after construction, allowing safe sharing in multi-threaded environments.

2. Modern Java Oriented JDK 17+ baseline allows full utilization of new features like Records and Sealed Classes.

3. Safer Default Configuration Date output in ISO-8601 better conforms to international standards, primitive type null checks are stricter, and polymorphic type validation is stricter.

4. Performance Optimized Multiple optimizations including BeanDescription lazy loading and RecyclerPool lazy initialization.

5. Dependencies Streamlined jackson-module-parameter-names, jackson-datatype-jdk8, jackson-datatype-jsr310 have been integrated into databind.

6. Simpler Exception Handling Unchecked exceptions eliminate the need for try-catch everywhere.

7. Ecosystem Rapidly Catching Up Spring Boot 4 defaults to Jackson 3, and mainstream frameworks like Netflix DGS have already supported it.

Notes on Jackson 3

1. Not an LTS Version Jackson 3.0 is a transitional version; 3.1 is the first LTS version. For production environments, it is recommended to upgrade directly to 3.1.x.

2. Numerous Breaking Changes Package names, class names, method names, exception system, and default configurations have all changed comprehensively; the upgrade workload is significant.

3. Ecosystem Dependencies Lagging Many third-party libraries are still using Jackson 2, such as Swagger. The good news is that Spring Boot 4 manages dependencies for both Jackson 2 and 3, allowing coexistence.

4. Migration Requires Systematic Planning It is recommended to use the OpenRewrite automated migration tool, or cooperate with Spring's spring.jackson.use-jackson2-defaults configuration for a gradual transition.

Applicable Scenarios

Scenario Recommendation Level Reason
New projects using Spring Boot 4 ✅✅✅ Highly Recommended Spring Boot 4 defaults to Jackson 3
High-concurrency systems pursuing thread safety ✅✅✅ Highly Recommended JsonMapper is immutable, thread-safe
Needing modern Java features ✅✅✅ Highly Recommended Records, Sealed Classes, etc.
Old projects upgrading to Spring Boot 4 ⚠️ Requires Careful Planning Many breaking changes, recommend using OpenRewrite to assist migration
Heavily dependent on Jackson 2 ecosystem libraries ⚠️ Requires Evaluation Although coexistence is possible, extra configuration is needed

11. Migration Suggestions

If you are preparing to upgrade to Jackson 3, I suggest following this order:

Step 1: Upgrade JDK to 17+

This is a hard requirement. If still on JDK 8/11, upgrade the JDK first.

Step 2: Upgrade Spring Boot to 4.x

Spring Boot 4 has fully embraced Jackson 3. Spring Boot 4 manages dependencies for both Jackson 2 and 3, allowing a smooth transition.

Step 3: Use OpenRewrite for Automated Migration

# OpenRewrite provides an automated migration recipe for Jackson 2→3
mvn rewrite:run -DactiveRecipes=org.openrewrite.java.jackson.UpgradeJackson_2_3

Step 4: Utilize Transitional Configuration

Spring Boot 4 provides the spring.jackson.use-jackson2-defaults configuration, which can temporarily maintain Jackson 2's default behavior as a 'safety net' during the transition period.

Step 5: Gradually Replace Code

For more project practices, visit my technical website: susan.net.cn/project

12. Final Thoughts

Returning to the initial question: Jackson 3 is here, what are the new features?

It's not as simple as adding a few new annotations or fixing a few bugs.

Jackson 3 is a thorough architectural upgrade — from the JDK baseline to package names, from API design to the exception system, from default configurations to performance optimization, everything has been reorganized.

Jackson 3.0 was officially released as a GA version on October 3, 2025. From its inception at the end of 2017 to its official release, it underwent nearly 8 years of refinement.

And Spring Boot 4 has already adopted it as the default JSON library; the entire Java ecosystem is accelerating its migration to Jackson 3.

But be mentally prepared before upgrading — Jackson 3 has a huge number of breaking changes. Package names changed, class names changed, method names changed, exception types changed, and default behaviors changed. This is not a 'seamless upgrade'.

The good news is that Spring Boot 4 manages dependencies for both Jackson 2 and 3, allowing you to migrate gradually. Jackson 2.21 is still an LTS version and will not disappear in the short term.

My suggestion is: New projects should go directly to Jackson 3; old projects should follow the Spring Boot 4 upgrade, utilize spring.jackson.use-jackson2-defaults for transition, and gradually complete the migration. If there are too many dependent libraries that cannot all be upgraded in the short term, coexistence of Jackson 2 and 3 is also a feasible solution.

Comments

Top 2 from juejin.cn, machine-translated. The original thread is authoritative.

用户9783319361854

In practice, it's just one sentence: help me upgrade to Spring Boot 4 and verify. Then go make coffee and wait for the result.

星之夜雨

Learned something.