Add Jackson 3 support for Keycloak Admin Client - #50848
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Jackson 3 support to the Keycloak Admin Client while retaining Jackson 2 compatibility.
Changes:
- Extracts Jackson-independent client code into
keycloak-admin-client-core. - Adds Jackson 3 REST, mapper, serializer, and service-provider implementations.
- Introduces JSON abstractions and Jackson 3 CI profiles for Admin API v1 and v2.
Reviewed changes
Copilot reviewed 64 out of 148 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
.github/actions/conditional/action.yml |
Exposes the Jackson 3 CI condition. |
.github/actions/conditional/conditions |
Selects changes requiring Jackson 3 tests. |
.github/workflows/ci.yml |
Runs Jackson 3 admin-client tests. |
integration/pom.xml |
Registers the new client modules. |
integration/admin-client/pom.xml |
Makes Jackson 2 client depend on shared core. |
integration/admin-client-core/pom.xml |
Defines the Jackson-independent client module. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/Config.java |
Moves client configuration into shared core. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/CreatedResponseUtil.java |
Moves response utilities into shared core. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/Keycloak.java |
Moves main client implementation into shared core. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/KeycloakBuilder.java |
Moves the client builder into shared core. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/spi/ResteasyClientProvider.java |
Defines the REST client provider SPI. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/token/TokenManager.java |
Moves token management into shared core. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/token/TokenService.java |
Moves the token endpoint proxy into shared core. |
integration/admin-client-core/src/main/java/org/keycloak/admin/client/resource/* |
Moves Admin REST resource interfaces and filters into shared core. |
integration/admin-client-jackson3/pom.xml |
Defines the Jackson 3 client module and dependencies. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/JacksonProvider3.java |
Configures the Jackson 3 REST provider. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/Jackson3JsonMapper.java |
Implements the mapper SPI for Jackson 3. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/Jackson3RawJsonValueSupport.java |
Implements raw JSON operations for Jackson 3. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/KeycloakAnnotationIntrospector3.java |
Maps version-neutral annotations to Jackson 3 handlers. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/MultivaluedHashMapValueDeserializer3.java |
Adds Jackson 3 multivalued-map deserialization. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/MultivaluedHashMapValueSerializer3.java |
Adds Jackson 3 multivalued-map serialization. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/ResteasyClientClassicProvider3.java |
Supplies the Jackson 3 RESTEasy client. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/StreamDeserializer3.java |
Adds stream response deserialization. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/StringListMapDeserializer3.java |
Adds flexible string-list map deserialization. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/StringOrArrayDeserializer3.java |
Reads scalar-or-array string values. |
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/StringOrArraySerializer3.java |
Writes scalar-or-array string values. |
integration/admin-client-jackson3/src/main/resources/META-INF/services/org.keycloak.admin.client.spi.ResteasyClientProvider |
Registers the Jackson 3 REST provider. |
integration/admin-client-jackson3/src/main/resources/META-INF/services/org.keycloak.json.KeycloakJsonMapper |
Registers the Jackson 3 mapper. |
integration/admin-client-jackson3/src/main/resources/META-INF/services/org.keycloak.json.RawJsonValueSupport |
Registers Jackson 3 raw JSON support. |
core/src/main/java/org/keycloak/json/KeycloakJsonMapper.java |
Defines a version-neutral mapper SPI. |
core/src/main/java/org/keycloak/json/KeycloakJsonMapperFactory.java |
Loads the active mapper implementation. |
core/src/main/java/org/keycloak/json/RawJsonValue.java |
Introduces a version-neutral raw JSON wrapper. |
core/src/main/java/org/keycloak/json/RawJsonValueSupport.java |
Defines raw JSON navigation operations. |
core/src/main/java/org/keycloak/json/Jackson2JsonMapper.java |
Implements the mapper SPI for Jackson 2. |
core/src/main/java/org/keycloak/json/Jackson2RawJsonValueSupport.java |
Implements raw JSON operations for Jackson 2. |
core/src/main/java/org/keycloak/json/StringOrArray.java |
Introduces a scalar-or-array annotation. |
core/src/main/java/org/keycloak/json/StringListMap.java |
Introduces a flexible string-list map annotation. |
core/src/main/java/org/keycloak/json/MultivaluedHashMapValue.java |
Introduces a multivalued-map annotation. |
core/src/main/resources/META-INF/services/org.keycloak.json.KeycloakJsonMapper |
Registers the Jackson 2 mapper. |
core/src/main/resources/META-INF/services/org.keycloak.json.RawJsonValueSupport |
Registers Jackson 2 raw JSON support. |
core/src/main/java/org/keycloak/representations/** |
Replaces Jackson 2-specific representation types and annotations. |
core/src/main/java/org/keycloak/jose/jwe/JWE.java |
Uses the mapper SPI for JWE headers. |
core/src/main/java/org/keycloak/jose/jws/JWSBuilder.java |
Uses the mapper SPI for JWS serialization. |
core/src/main/java/org/keycloak/jose/jws/JWSHeader.java |
Uses the mapper SPI for header serialization. |
core/src/main/java/org/keycloak/jose/jws/JWSInput.java |
Uses the mapper SPI when reading headers. |
core/src/main/java/org/keycloak/util/JWKSUtils.java |
Uses the mapper SPI for thumbprints. |
core/src/main/java/org/keycloak/util/TokenUtil.java |
Uses the mapper SPI for token processing. |
core/src/test/java/org/keycloak/json/JacksonAgnosticRepresentationsTest.java |
Checks representations for Jackson 2-specific imports. |
services/src/main/java/org/keycloak/services/clientpolicy/ClientPoliciesUtil.java |
Unwraps version-neutral client-policy configuration. |
test-framework/builders/src/main/java/org/keycloak/testframework/realm/ClientPolicyBuilder.java |
Wraps condition configuration in RawJsonValue. |
test-framework/builders/src/main/java/org/keycloak/testframework/realm/ClientProfileBuilder.java |
Wraps executor configuration in RawJsonValue. |
tests/base/pom.xml |
Adds Jackson 3 Admin API v1 smoke tests. |
tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java |
Adapts OID4VC client-policy configuration. |
rest/admin-v2/tests/pom.xml |
Adds the Jackson 3 Admin API v2 profile. |
rest/admin-v2/tests/src/test/java/org/keycloak/tests/admin/client/v2/ClientPoliciesV2Test.java |
Adapts v2 policy configuration to raw JSON. |
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/policies/AbstractClientPoliciesTest.java |
Unwraps configuration for assertions. |
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientPoliciesUtil.java |
Wraps test policy configuration. |
6f14125 to
0c0dfde
Compare
| } | ||
|
|
||
| public JsonNode getConfiguration() { | ||
| public RawJsonValue getConfiguration() { |
There was a problem hiding this comment.
I can't keep the same type if it is not present in Jackson 3. It is "breaking", but hardly an issue considering I provide same methods that are relevant. If you tightly couple representation with underlying libraries, this is what you get.
| } | ||
|
|
||
| public JsonNode getConfiguration() { | ||
| public RawJsonValue getConfiguration() { |
There was a problem hiding this comment.
Same comment, same answer, read here: #50848 (comment)
| <profile> | ||
| <id>jackson3</id> | ||
| <dependencies> |
There was a problem hiding this comment.
keycloak-admin-client-tests is NOT on the classpath, therefore ResteasyClientClassicProvider and JacksonProvider that live in that module cannot be loaded. keycloak-admin-v2-services needs Jackson 2 for server, but it is not used by the client as Jackson 3 ignores Jackson 2 stuff which is relevant in this context.
| <profile> | ||
| <id>jackson3</id> | ||
| <dependencies> |
0c0dfde to
34ac05a
Compare
|
I am actually not completely sure which labels should this PR have, so I left such one I am sure and someone else can add additional. |
34ac05a to
770d8f7
Compare
770d8f7 to
08e5a91
Compare
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.cluster.RealmInvalidationClusterTest#crudWithFailoverKeycloak CI - Store IT (mssql) |
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0324a48 to
61d82c4
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 73 out of 157 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
integration/admin-client-jackson3/src/main/java/org/keycloak/admin/client/jackson3/KeycloakAnnotationIntrospector3.java:37
- The Jackson 3 CI selections do not exercise either of these adapters: the selected v1 smoke tests and admin-v2 tests contain no workflow serialization or
AuthorizationSchemadeserialization, and this module has no focused tests. Add Jackson 3 round-trip tests for@MultivaluedHashMapValueand both array/object forms of@ResourceTypeMap, matching the existing Jackson 2 behavior.
Closes: keycloak#48216 Signed-off-by: Michal Vavřík <dev@michalvavrik.net>
61d82c4 to
c7f8276
Compare
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 74 out of 158 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
core/src/test/java/org/keycloak/json/JacksonAgnosticRepresentationsTest.java:62
- This guard only examines
importlines, so a representation can still use a forbidden Jackson 2 type via a fully qualified name (for example,com.fasterxml.jackson.databind.JsonNode) and the test passes. Inspect compiled dependencies or otherwise cover fully qualified type references so the test actually enforces the stated Jackson-agnostic contract.
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (keeps RawJsonValue from upstream, no Jackson 2 jackson-databind needed) - Add admin-client-jackson3 module bundling core + Jackson 3 providers, depends on client-common-synced-jackson3 - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue→JsonNode cleanup for Jackson 2 module, no cleanup for Jackson 3 module - Add Jackson 3 test profile to admin-client-tests No breaking API changes for existing Jackson 2 users. Jackson 3 users get RawJsonValue (new module, no existing users to break). Alternative approach to jackson3-keep-rawjsonvalue which uses a single shared representations module with RawJsonValue for both Jackson versions. Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add client-common-synced-jackson3 module (jackson-agnostic representations, no jackson 2 deps) - Add admin-client-jackson3 module bundling core + jackson 3 providers - Add keycloak-admin-client-core to admin-client sync profile - Sync script: dynamic RawJsonValue->JsonNode cleanup for jackson 2, annotation stripping for jackson 3 - Jackson 3 test profile + JsonMapper reflection bridge for test compatibility - CI workflow for jackson 3 tests - Release notes Closes: keycloak/keycloak#48216 See: keycloak/keycloak#50848 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
I am sorry for the noise, I let claude play in their playground on a GH workflow for a combined nightly sync + PR CI and wow, there is 100+ links 😀. I'll avoid that in the future. @shawkins you mentioned it was a breaking change (and so did Copilot), but I think I managed to workaround that in IMO stable way on the Keycloak client side until their release 27.x, Because @mposolda I opened a draft PR as requested keycloak/keycloak-client#233 and I prepared a run that you can inspect which tests both Jackson 2 and Jackson 3:
|
mposolda
left a comment
There was a problem hiding this comment.
@michalvavrik Thanks for the updates and for the draft PR to keycloak-client!
Approving this PR, but did not deep review. Approving just the approach and general direction. Would be good to have more proper reviews from members of cloud-native team.
shawkins
left a comment
There was a problem hiding this comment.
LGTM, thank you @michalvavrik
Pepo48
left a comment
There was a problem hiding this comment.
My concerns were addressed properly, thanks Michal!
Uh oh!
There was an error while loading. Please reload this page.