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,
nullwhere 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
JsonSerializertoValueSerializer,JsonDeserializertoValueDeserializerandSerializerProvidertoSerializationContext; ObjectMapperis immutable and is configured through a builder, such asJsonMapper.builder();- support for
java.time,Optionaland constructor parameter names is built intojackson-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:
Jackson2ObjectMapperBuilderCustomizerbecomesJsonMapperBuilderCustomizer;@JsonComponentbecomes@JacksonComponent, and@JsonMixinbecomes@JacksonMixin;JsonObjectSerializerbecomesObjectValueSerializer, andJsonValueDeserializerbecomesObjectValueDeserializer.
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_ALPHABETICALLYis on, so a class without@JsonPropertyOrdercan write its fields in a different order. - Enum values.
WRITE_ENUMS_USING_TO_STRINGandREAD_ENUMS_USING_TO_STRINGare on: an enum with its owntoString()writes and reads that text instead of its name. - Property names.
FIX_FIELD_NAME_UPPER_CASE_PREFIXis on, which changes how names such asiPhoneare derived, mostly in Lombok classes. Getters such asget_value()orgeturl()are no longer detected, so their properties can drop out of the output. - Inbound payloads.
FAIL_ON_NULL_FOR_PRIMITIVESandFAIL_ON_TRAILING_TOKENSare on:nullfor anintfails, 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=falseturns 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
- Spring Boot 4.0 Migration Guide, Spring
- Spring Boot 4.0 Release Notes, Spring
- Spring Boot 4.1 Release Notes, Spring
- Spring Boot 4.0 Configuration Changelog, Spring
- JSON, Spring
- Spring MVC, Spring
- Spring MVC, Spring
- Testing Spring Boot Applications, Spring
- JsonContentAssert (Spring Boot 4.1.1 API), Spring
- JsonContent (Spring Boot 4.1.1 API), Spring
- Spring Boot, Spring
- Jackson Release 3.0, FasterXML
- Jackson Release 3.1, FasterXML
- Jackson 3 Migration Guide, FasterXML

