Skip to content

feat: migrate from Jackson 2 to Jackson 3 (tools.jackson) for Spring Boot 4 native support#2306

Closed
StringKe wants to merge 1 commit into
Netflix:masterfrom
StringKe:feature/jackson3-migration
Closed

feat: migrate from Jackson 2 to Jackson 3 (tools.jackson) for Spring Boot 4 native support#2306
StringKe wants to merge 1 commit into
Netflix:masterfrom
StringKe:feature/jackson3-migration

Conversation

@StringKe
Copy link
Copy Markdown

@StringKe StringKe commented Apr 25, 2026

Pull request checklist

  • Please read our contributor guide
  • Consider creating a discussion on the discussion forum first
  • Make sure the PR doesn't introduce backward compatibility issues
  • Make sure to have sufficient test cases

Pull Request type

  • Bugfix
  • Feature
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Other (please describe):

Changes in this PR

Migrates the entire DGS Framework from Jackson 2 (com.fasterxml.jackson.*) to Jackson 3 (tools.jackson.*) so that DGS aligns natively with Spring Boot 4 / Spring Framework 7, where tools.jackson.databind.json.JsonMapper replaces com.fasterxml.jackson.databind.ObjectMapper as the default mapper.

Issue #2284, also addresses the underlying Jackson 3 conflict reported in #2296.

What changed

  • BaseDgsQueryExecutor.objectMapper is now a JsonMapper built via the Jackson 3 builder pattern. Public field type changes from ObjectMapper to JsonMapper.
  • JsonPath integration switches to json-path 3.0.0's Jackson3JsonProvider and Jackson3MappingProvider. The platform BOM bumps json-path from 2.9.0 to 3.0.0; Spring Boot 4's pin is overridden via the json-path.version property.
  • graphql-dgs-client public APIs accept JsonMapper instead of ObjectMapper across GraphQLClient, MonoGraphQLClient, WebClientGraphQLClient, RestClientGraphQLClient, GraphQLResponse, and the SSE/WebSocket variants.
  • GraphQLRequestOptions custom serializer/deserializer extends Jackson 3's ValueSerializer<T> / ValueDeserializer<T> (renamed from JsonSerializer / JsonDeserializer). The serialize override receives SerializationContext (renamed from SerializerProvider).
  • MultipartFileSerializer extends Jackson 3 StdSerializer; writeStringField is renamed to writeStringProperty per the J3 streaming API.
  • Drop jackson-datatype-jdk8, jackson-module-parameter-names, and jackson-datatype-jsr310 dependencies. JDK 8 / parameter-names / java.time support is built into tools.jackson.databind 3.x and discovered automatically.
  • READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE moved from DeserializationFeature to tools.jackson.databind.cfg.EnumFeature in J3.
  • WRITE_DATES_AS_TIMESTAMPS moved from SerializationFeature to tools.jackson.databind.cfg.DateTimeFeature in J3.
  • FAIL_ON_NULL_FOR_PRIMITIVES is explicitly disabled on BaseDgsQueryExecutor.objectMapper because Jackson 3 flipped its default to true. DGS GraphQL responses regularly omit non-selected primitive fields and would otherwise break extractValueAsObject.
  • JPMS module-info requires clauses updated from com.fasterxml.jackson.* to tools.jackson.* (databind/core/datatype/module). The annotation module remains com.fasterxml.jackson.annotation because Jackson 3 deliberately reuses the existing Jackson 2 jackson-annotations artifact (resolved to 2.20 in this build via Spring Boot 4's jackson-2-bom) — annotation classes (JsonProperty, JsonCreator, JsonIgnoreProperties, JsonSubTypes, JsonTypeInfo, etc.) are unchanged in Jackson 3.
  • OperationMessageTest's malformed-JSON assertion broadens from DatabindException to JacksonException; in Jackson 3 parser-level failures throw StreamReadException, a sibling of DatabindException under JacksonException.
  • All dependencies.lock files regenerated with the new resolutions.

Breaking changes

  • Public APIs that previously accepted com.fasterxml.jackson.databind.ObjectMapper (BaseDgsQueryExecutor.objectMapper, GraphQLClient.createCustom, WebClientGraphQLClient, RestClientGraphQLClient, GraphQLResponse, MonoGraphQLClient and the custom variants) now require tools.jackson.databind.json.JsonMapper. There is no compatibility shim; callers must migrate.
  • Custom client-side ValueSerializer / ValueDeserializer implementations must extend the new Jackson 3 base classes; serialize() takes SerializationContext, deserialize() takes DeserializationContext.
  • json-path is forced to 3.0.0 (overrides Spring Boot 4's 2.9.0 pin); consumers that use json-path APIs transitively through DGS may need to adjust to json-path 3.x.

Verification

  • ./gradlew check is green (compile, ktlint, all tests across every module).
  • grep -rn "com.fasterxml.jackson" --include='*.kt' --include='*.kts' --include='*.java' . returns only jackson-annotations references, which is intentional — Jackson 3 deliberately reuses the Jackson 2 annotations artifact.

Issue #2284

Alternatives considered

  • Dual-stack with spring-boot-jackson2 compatibility shim: keeps Jackson 2 alongside Jackson 3 via the Spring Boot 4 bridge module. Rejected because the goal is for DGS to natively align with the Spring Boot 4 default (Jackson 3) without forcing every consumer to drag in the deprecated Jackson 2 module. org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration is annotated @Deprecated(since = "4.0.0", forRemoval = true) and the Spring Boot Javadoc states it will be removed in Spring Boot 4.3.0 in favor of Jackson 3.
  • Hybrid migration retaining ObjectMapper-typed public APIs as deprecated: would soften the break but contradicts the request in feature: Support Jackson 3 in DGS #2284 for native Jackson 3 support. The annotation classes are reused as-is precisely because they did not need to change; the rest of the API rename was unavoidable per the Jackson 3 design.
  • Wait for an upstream maintainer-driven migration: feature: Support Jackson 3 in DGS #2284 has been open since 2026-03 with no implementation progress and bug: DGS 11.1.0 imports Jackson3 even though only Jackon2 is supports #2296 confirms the current 11.1.x line is incoherent under Spring Boot 4. Submitting this PR unblocks downstream Spring Boot 4 adopters today.

Migrates the entire DGS Framework from Jackson 2 (com.fasterxml.jackson.*) to
Jackson 3 (tools.jackson.*) so that DGS aligns natively with Spring Boot 4
and Spring Framework 7 (where the default ObjectMapper is replaced by
tools.jackson.databind.json.JsonMapper).

Refs Netflix#2284, Netflix#2296

What changed:
- BaseDgsQueryExecutor.objectMapper is now a JsonMapper built via the
  Jackson 3 builder pattern. Public field type changes from ObjectMapper
  to JsonMapper.
- JsonPath integration switches to json-path 3.0.0's Jackson3JsonProvider
  and Jackson3MappingProvider (the platform BOM bumps json-path from 2.9.0
  to 3.0.0; Spring Boot's pin is overridden via the json-path.version
  property).
- graphql-dgs-client public APIs now accept JsonMapper instead of
  ObjectMapper across GraphQLClient, MonoGraphQLClient,
  WebClientGraphQLClient, RestClientGraphQLClient, GraphQLResponse, and
  the SSE/WebSocket variants.
- GraphQLRequestOptions custom serializer/deserializer extends Jackson 3's
  ValueSerializer<T>/ValueDeserializer<T> (renamed from JsonSerializer/
  JsonDeserializer). The serialize override receives SerializationContext
  (renamed from SerializerProvider).
- MultipartFileSerializer extends Jackson 3 StdSerializer; writeStringField
  is renamed to writeStringProperty per the Jackson 3 streaming API.
- Drop dependencies on jackson-datatype-jdk8, jackson-module-parameter-names,
  and jackson-datatype-jsr310. JDK 8 / parameter-names / java.time support
  is built into jackson-databind 3.x and discovered automatically.
- READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE moved from
  DeserializationFeature to tools.jackson.databind.cfg.EnumFeature in J3.
- WRITE_DATES_AS_TIMESTAMPS moved from SerializationFeature to
  tools.jackson.databind.cfg.DateTimeFeature in J3.
- FAIL_ON_NULL_FOR_PRIMITIVES is now disabled explicitly on
  BaseDgsQueryExecutor.objectMapper because Jackson 3 flipped its default
  to true; DGS GraphQL responses regularly omit non-selected primitives
  and would otherwise break extractValueAsObject.
- JPMS module-info requires clauses updated from com.fasterxml.jackson.*
  to tools.jackson.* (databind/core/datatype/module). The annotation
  module remains com.fasterxml.jackson.annotation because Jackson 3
  intentionally reuses the Jackson 2 jackson-annotations 2.21 jar — the
  annotation classes (JsonProperty, JsonCreator, JsonIgnoreProperties,
  JsonSubTypes, JsonTypeInfo, etc.) are unchanged in Jackson 3.
- OperationMessageTest's malformed-JSON assertion broadens from
  DatabindException to JacksonException; in Jackson 3 parser-level
  failures throw StreamReadException, a sibling of DatabindException
  under JacksonException.
- All dependency-lock files regenerated with the new resolutions.

BREAKING CHANGES
- Public APIs that previously accepted com.fasterxml.jackson.databind.ObjectMapper
  (BaseDgsQueryExecutor.objectMapper, GraphQLClient.createCustom,
  WebClientGraphQLClient, RestClientGraphQLClient, GraphQLResponse,
  MonoGraphQLClient and the custom variants) now require
  tools.jackson.databind.json.JsonMapper. There is no compatibility shim;
  callers must migrate.
- Custom client-side ValueSerializer/ValueDeserializer implementations
  must extend the new Jackson 3 base classes; serialize() takes
  SerializationContext, deserialize() takes DeserializationContext.
- json-path is forced to 3.0.0 (overrides Spring Boot 4's 2.9.0 pin);
  consumers using json-path APIs transitively through DGS may need to
  adjust to json-path 3.x.
@jjacobs44
Copy link
Copy Markdown
Collaborator

Closing since we've released Jackson3 support in v12.0.0. It's most similar to your first alternative considered

Dual-stack with spring-boot-jackson2 compatibility shim: keeps Jackson 2 alongside Jackson 3 via the Spring Boot 4 bridge module. Rejected because the goal is for DGS to natively align with the Spring Boot 4 default (Jackson 3) without forcing every consumer to drag in the deprecated Jackson 2 module.

But the way we've implemented it does not force Jackson2 on the classpaths of those who want to fully embrace Jackson3. Please feel free to open an issue if you're having trouble with the released solution.

@jjacobs44 jjacobs44 closed this Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants