On this page

Spring Boot 4 maps JSON with Jackson 3, and an integration service meets four changes: new package and group names under tools.jackson, new defaults that can reorder fields or change enum values, unchecked exceptions, and renamed Spring Boot properties and customizers. Record the payloads on Spring Boot 3.5 first, then compare them byte for byte after every step.

Record the payloads before you change anything

#

Spring Boot 4 makes Jackson 3, a new major version, its default JSON library. Before the version changes, capture what the service writes and reads on 3.5.16, the last open-source release of Spring Boot 3.5. The whole path is in Spring Boot 4 and Java 25: an upgrade path for integration services.

For each interface the service offers or calls, store these as files in the repository, exactly as written:

  • every response body and every outbound message;
  • inbound samples, the awkward ones included: unknown fields, null where a number is expected, enum values, dates and empty values;
  • the error bodies the service returns for a payload it cannot read.

Every later step is compared with these files.

Change the group IDs and the imports

#

Jackson 3 moves its Maven group IDs and Java packages from com.fasterxml.jackson to tools.jackson. The exception is jackson-annotations: it keeps the group ID com.fasterxml.jackson.core and the package com.fasterxml.jackson.annotation, so @JsonProperty and @JsonFormat keep their imports. Spring Boot 4.1.1 manages Jackson 3.1.5, and Jackson 3.1 is the first long-term support line of Jackson 3.

Annotations inside jackson-databind, such as @JsonSerialize, @JsonDeserialize and @JsonNaming, do move, to tools.jackson.databind.annotation. The Jackson migration guide warns of a silent failure: if jackson-databind 2.x is still on the classpath, often transitively, the old import compiles and Jackson 3 ignores the annotation, with no error and no warning. Search the sources for com.fasterxml.jackson.databind, and the dependency tree for com.fasterxml.jackson.core:jackson-databind.

Three more changes are mechanical:

  • core types are renamed, for example JsonSerializer to ValueSerializer, JsonDeserializer to ValueDeserializer and SerializerProvider to SerializationContext;
  • ObjectMapper is immutable and is configured through a builder, such as JsonMapper.builder();
  • support for java.time, Optional and constructor parameter names is built into jackson-databind, so the separate modules and their registrations go.

Rename what Spring Boot configures

#

Spring Boot 4 renames its own Jackson classes to match Jackson 3:

  • Jackson2ObjectMapperBuilderCustomizer becomes JsonMapperBuilderCustomizer;
  • @JsonComponent becomes @JacksonComponent, and @JsonMixin becomes @JacksonMixin;
  • JsonObjectSerializer becomes ObjectValueSerializer, and JsonValueDeserializer becomes ObjectValueDeserializer.

Spring Boot auto-configures a JsonMapper for JSON. An ObjectMapper bean of your own no longer replaces it: define a JsonMapper bean, marked @Primary, and know that it switches off Spring Boot’s auto-configuration of the mapper.

The properties move too. spring.jackson.parser.* and spring.jackson.generator.* are removed, and the features specific to JSON sit under spring.jackson.json.read.* and spring.jackson.json.write.*. A parser feature whose Jackson 3 equivalent is not a JsonReadFeature is set in a JsonMapperBuilderCustomizer. Jackson 3 also moves the date and time features into DateTimeFeature and the enum features into EnumFeature, so spring.jackson.serialization.write_dates_as_timestamps becomes spring.jackson.datatype.datetime.write_dates_as_timestamps.

In Spring Boot 4.1, spring.jackson.read.* and spring.jackson.write.* hold the features common to several formats, such as CBOR, JSON and XML. The spring-boot-properties-migrator module reports renamed properties at start-up and migrates them while it runs; remove it once the move is done.

For the message converters, the HttpMessageConverters type is deprecated: ServerHttpMessageConvertersCustomizer and ClientHttpMessageConvertersCustomizer take its place.

The Jackson 3 defaults that can change your output

#

Jackson 3 changes many defaults. Four of them match what Spring Boot 3.5 already set for Jackson 2: dates and durations are not written as timestamps, unknown properties do not fail, and default view inclusion is off. Those four leave a Spring Boot service as it was. The ones that can change it:

  • Property order. MapperFeature.SORT_PROPERTIES_ALPHABETICALLY is on, so a class without @JsonPropertyOrder can write its fields in a different order.
  • Enum values. WRITE_ENUMS_USING_TO_STRING and READ_ENUMS_USING_TO_STRING are on: an enum with its own toString() writes and reads that text instead of its name.
  • Property names. FIX_FIELD_NAME_UPPER_CASE_PREFIX is on, which changes how names such as iPhone are derived, mostly in Lombok classes. Getters such as get_value() or geturl() are no longer detected, so their properties can drop out of the output.
  • Inbound payloads. FAIL_ON_NULL_FOR_PRIMITIVES and FAIL_ON_TRAILING_TOKENS are on: null for an int fails, and so does content after the JSON value.
  • Modules. Spring Boot 4 registers every Jackson module it finds on the classpath, where Spring Boot 3 registered only well-known ones. spring.jackson.find-and-add-modules=false turns this off.

Spring Boot offers a bridge. With spring.jackson.use-jackson2-defaults=true, the auto-configured JsonMapper uses defaults as close as possible to those of Spring Boot 3 with Jackson 2. Close is not identical, so the tests still decide. To keep one old behaviour on purpose, set it by name:

spring.jackson.mapper.sort_properties_alphabetically=false
spring.jackson.datatype.enum.write_enums_using_to_string=false

Jackson 3 exceptions are unchecked and renamed

#

Every Jackson 3 exception is a RuntimeException. JsonProcessingException becomes JacksonException, which no longer extends IOException. JsonMappingException becomes DatabindException, and JsonParseException and JsonGenerationException become StreamReadException and StreamWriteException.

A catch (IOException e) therefore no longer catches a Jackson error. Check each error path: the status and body of an error response, and what a message listener does with a payload it cannot read. The messages change as well. An unknown-property error says “property” where Jackson 2 said “field”, so an error body that carries Jackson’s message changes with it.

Jackson 2 as a stop-gap

#

Spring Boot 4 still ships Jackson 2 support, in the deprecated spring-boot-jackson2 module, which Spring calls a stop-gap for teams that need more time. Its properties sit under spring.jackson2.*, equivalent to the spring.jackson.* properties of Spring Boot 3.5. With both versions on the classpath, spring.http.converters.preferred-json-mapper=jackson2 makes Spring MVC and the imperative HTTP clients use Jackson 2. A library that still needs Jackson 2 can keep its own ObjectMapper beside Spring Boot’s Jackson 3 mapper.

The module lets you move the Spring Boot version and the JSON mapping in two steps, so that a failing test has one cause. Do not plan to stay on it. The Spring Boot 4.1 documentation says Jackson 2 support will be removed in a future Spring Boot 4.x release, and open-source support for Spring Boot 4.1 ends on 31 July 2027.

Prove the payloads stay byte for byte the same

#

@JsonTest auto-configures the JSON mapper with the service’s @JacksonComponent beans and Jackson modules, and an autowired JacksonTester writes and reads with it. Its isEqualToJson compares leniently, so it can pass when the bytes differ. For a byte-for-byte check, compare the text: getJson() returns the JSON string, and a plain string assertion fails on any changed byte, field order included.

@JsonTest
class OrderPayloadTests {

    @Autowired
    JacksonTester<Order> json;

    @Test
    void writesTheRecordedPayload() throws Exception {
        String recorded = Files.readString(Path.of("src/test/resources/payloads/order.json"));
        assertThat(json.write(TestOrders.sample()).getJson()).isEqualTo(recorded);
    }
}

Run the same comparison through the running application’s HTTP layer, where the message converters and their customizers apply. Parse each recorded inbound sample and assert the same object, or the same error. Each difference is a decision: pin the old behaviour in code, or accept the change and tell the systems that read the payload before you release.

The versions and dates in this article were checked on 19 October 2026 against spring.io, docs.spring.io and the Jackson project’s pages on GitHub. How we plan and carry out the move is on the page Spring Boot 3.5 to 4 upgrade.

Questions

Can we keep Jackson 2 on Spring Boot 4?

You can keep Jackson 2 for a while, through the deprecated spring-boot-jackson2 module that Spring Boot 4 ships as a stop-gap. The Spring Boot 4.1 documentation says Jackson 2 support will be removed in a future Spring Boot 4.x release.

Will our JSON output change after the move to Spring Boot 4?

Your JSON output can change, because Jackson 3 changes defaults that reach the payload: it sorts properties alphabetically and writes an enum with its toString() value. Compare the payloads recorded on Spring Boot 3.5 with the new ones, byte for byte, before you release.

Does spring.jackson.use-jackson2-defaults keep our payloads the same?

The property brings the defaults as close as possible to those of Spring Boot 3 with Jackson 2, which is not the same as identical bytes. Use it as a bridge and keep the byte-for-byte tests.

Which imports change from com.fasterxml.jackson to tools.jackson?

Every Jackson import changes to tools.jackson except those of jackson-annotations, such as @JsonProperty and @JsonFormat, which keep com.fasterxml.jackson.annotation. Annotations inside jackson-databind, such as @JsonSerialize, move to tools.jackson.databind.annotation.

Sources

  1. Spring Boot 4.0 Migration Guide, Spring
  2. Spring Boot 4.0 Release Notes, Spring
  3. Spring Boot 4.1 Release Notes, Spring
  4. Spring Boot 4.0 Configuration Changelog, Spring
  5. JSON, Spring
  6. Spring MVC, Spring
  7. Spring MVC, Spring
  8. Testing Spring Boot Applications, Spring
  9. JsonContentAssert (Spring Boot 4.1.1 API), Spring
  10. JsonContent (Spring Boot 4.1.1 API), Spring
  11. Spring Boot, Spring
  12. Jackson Release 3.0, FasterXML
  13. Jackson Release 3.1, FasterXML
  14. Jackson 3 Migration Guide, FasterXML