Skip to content

Migrate from JSON-B to Jackson - #2543

Merged
phillip-kruger merged 3 commits into
smallrye:mainfrom
jmartisk:jackson
Jul 2, 2026
Merged

Migrate from JSON-B to Jackson#2543
phillip-kruger merged 3 commits into
smallrye:mainfrom
jmartisk:jackson

Conversation

@jmartisk

@jmartisk jmartisk commented Jun 25, 2026

Copy link
Copy Markdown
Member

Breaking Changes

Client API type changes

  • Response.getData() now returns Jackson ObjectNode instead of jakarta.json.JsonObject
  • Response.getExtensions() returns ObjectNode instead of JsonObject
  • Request.toJsonObject() returns ObjectNode instead of JsonObject
  • TypesafeResponse.getExtensions() returns ObjectNode instead of JsonObject
  • All code using JSON-P methods on these return types (.getString(), .getInt(), .getJsonObject(), .getJsonArray(),
    .containsKey()) must switch to Jackson equivalents (.get().asText(), .get().asInt(), .get(), .has())

Server SPI change

  • EventingService.overrideJsonbConfig() replaced by overrideObjectMapperConfig() — implementations must return
    Map<String, ObjectMapper> instead of Map<String, Jsonb>

Dependency changes

  • jakarta.json-api (JSON-P) and jakarta.json.bind-api (JSON-B) are no longer transitively provided
  • org.eclipse:yasson is no longer a dependency
  • Applications that imported these transitively through SmallRye GraphQL need to add them explicitly if used elsewhere

What Still Works (No Changes Needed)

  • @JsonbProperty, @JsonbTransient, @JsonbCreator, @JsonbNillable on user POJOs — honored at both schema-build and runtime
    via the compatibility module
  • @JsonbDateFormat and @JsonbNumberFormat — formatting behavior preserved
  • @JsonbTypeInfo / @JsonbSubtype for polymorphic types — still works for both schema and runtime
  • All Jackson annotations (@JsonProperty, @JsonIgnore, @JsonCreator, @jsonformat) — continue to work, now handled
    natively
  • MicroProfile GraphQL annotations (@name, @ignore, @query, @mutation, @GraphQLAPI) — unchanged
  • @AdaptWith — unchanged
  • jakarta.json.JsonObject as a GraphQL scalar type (the "JSON" scalar) — still supported

Considerations

  • Jackson is now the JSON engine — its serialization behavior may differ subtly from Yasson (e.g., field ordering, number
    formatting, null handling)
  • BigDecimal precision is preserved (no truncation to double)
  • Integer/long overflow is now detected and throws InvalidResponseException (previously might have silently truncated)
  • If you use PayloadCreator or similar test utilities that build request JSON with
    jakarta.json.Json.createObjectBuilder(), switch to Jackson ObjectMapper.createObjectNode()

@jmartisk

jmartisk commented Jun 25, 2026

Copy link
Copy Markdown
Member Author

@geoand ,so, I would probably do this as the intermediary first step, and when we have some basic usable Quarkus migration to Jackson 3, I would migrate this to Jackson 3. I guess that shouldn't be too hard at that point, or?
Do you agree with this plan? If you see anything that will be hard to migrate to 3, let me know. I'm not well acquainted with the 2->3 changes

@jmartisk

jmartisk commented Jun 25, 2026

Copy link
Copy Markdown
Member Author

I've sent quarkusio/quarkus#55086 with the quarkus work. I ran the Quarkus tests (incl. native) locally and they pass.

@geoand

geoand commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Sure, that should work

@phillip-kruger

Copy link
Copy Markdown
Member

@jmartisk - at the moment the TCK is disabled. We need to get this (#2392) in so we can test this against the TCK. I did it locally and I get some failures in the tests. From a spec p.o.v we support using JsonB annotations (as this is part of the MicroProfile landscape). So as an example we can use JsonbAdapter (rather than the graphql adapter) and this should still work. Those are some of the TCK failures

@jmartisk

Copy link
Copy Markdown
Member Author

You mean that the TCK tests JsonbAdapter functionality? That's the one thing that I dropped support for. I guess we could try to reintroduce it somehow, but without actually using JSON-B it might be problematic

@phillip-kruger

Copy link
Copy Markdown
Member

Yes. In general though the spec add full support for JsonB. The adaptor part is not yet in the spec, only in the SmallRye Spec and TCK extension tests. But those are not run either (as they all run under the TCK test).

@phillip-kruger

Copy link
Copy Markdown
Member

Hi @jmartisk, I pushed a fix commit on top of your Jackson migration.

I tested this PR locally by merging it with the TCK re-enablement PR (#2392) and running the full TCK. The original PR had 8 TCK failures, all traced back to @JsonbTypeAdapter support being removed. Since JSON-B is part of the MicroProfile umbrella specs, we need to keep supporting these annotations — but using the existing AdaptWith infrastructure under the hood.

Here's what the fix commit addresses:

1. Restore @JsonbTypeAdapter support in schema builder (AdaptWithHelper)
The PR replaced the @JsonbTypeAdapter handling with a warning log. The fix restores it by converting @JsonbTypeAdapter to the internal AdaptWith model at schema-build time (same approach as before). This ensures the GraphQL schema correctly reflects the adapted types.

2. Remove isJsonB() exclusion in InputFieldsInfo
With JSON-B (Yasson) as the runtime, @JsonbTypeAdapter fields were excluded from explicit adapter invocation because Yasson handled them automatically during deserialization. With Jackson as the runtime, that no longer happens — Jackson doesn't know about @JsonbTypeAdapter. Removing the !isJsonB() check ensures these adapters are invoked explicitly at runtime, just like @AdaptWith adapters.

3. Add ComplexMapKeys module to JacksonCreator
Jackson eagerly validates all fields of a target type during deserialization — including Map<ComplexKey, ...> fields that aren't even present in the JSON input. Unlike JSON-B which lazily resolves deserializers, Jackson fails at type preparation time with Cannot find a (Map) Key deserializer for type ComplexKey. The fix registers a KeyDeserializers provider that handles user-defined POJO key types by deserializing them from their JSON string representation.

4. Fix micrometer property name typo
<verison.io.micrometer><version.io.micrometer> (both the property definition and its usage). Without this fix, the build fails immediately.

After these fixes, all 387 TCK tests pass when merged with #2392.

@phillip-kruger

Copy link
Copy Markdown
Member

The core SmallRye builds (JDK 17, 21, 25) all pass after the rebase. The remaining Quarkus test failures are a pre-existing issue from the Jackson migration — they're not related to the rebase or the fix commit.

The root cause is the breaking client API change where Response.getData() now returns Jackson ObjectNode instead of JSON-P JsonObject. The Quarkus GraphQL client extension tests still call JSON-P methods like getString() on the response data, which don't exist on ObjectNode:

cannot find symbol
  symbol:   method getString(java.lang.String)
  location: class com.fasterxml.jackson.databind.node.ObjectNode

Affected Quarkus test files:

  • DynamicGraphQLClientInjectionTest.java
  • DynamicGraphQLClientInjectionWithQuarkusConfigTest.java
  • DynamicGraphQLClientWebSocketAuthenticationTest.java
  • DynamicGraphQLClientWebSocketAuthenticationClientInitTest.java
  • DynamicGraphQLClientTlsReloadApplicationScopedTest.java

These tests need to be updated in the Quarkus extension to use ObjectNode.get("field").asText() instead of JsonObject.getString("field").

@jmartisk

jmartisk commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

For Quarkus-side tests, you should use my branch quarkusio/quarkus#55175

@jmartisk
jmartisk marked this pull request as ready for review July 1, 2026 05:40
Comment thread pom.xml Outdated
The Jackson migration PR dropped @JsonbTypeAdapter support entirely, but
this annotation is part of the MicroProfile spec (JSON-B) and must keep
working. This commit restores it by converting @JsonbTypeAdapter to the
internal AdaptWith model at schema-build time, and ensures the runtime
adapter invocation works with Jackson instead of relying on JSON-B to
handle it automatically.

Fixes:
- Restore @JsonbTypeAdapter handling in AdaptWithHelper (schema builder)
- Remove isJsonB() exclusion in InputFieldsInfo so JsonB adapters are
  invoked explicitly at runtime (Jackson does not handle them)
- Add ComplexMapKeys module to JacksonCreator for Map fields with
  non-trivial key types that Jackson cannot deserialize by default
- Fix micrometer property name typo (verison -> version)
- Replace .collect(Collectors.toList()) with .toList() (JDK 17+)
- Add missing imports in ResponseImpl and JsonbAnnotationIntrospectorTest
- Use property for jakarta.json.bind-api version instead of hardcoding

@phillip-kruger phillip-kruger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jmartisk and @mskacelik !

@phillip-kruger
phillip-kruger merged commit 36d0564 into smallrye:main Jul 2, 2026
5 of 7 checks passed
@github-actions github-actions Bot added this to the 2.12.3 milestone Jul 2, 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.

4 participants