From 7d224018c1445e6b8238451890a73d133c7deaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Tue, 20 Feb 2024 20:02:20 +0100 Subject: [PATCH] Fix Keycloak Admin Client Classic with RESTEasy JSONB --- .../KeycloakAdminClientProcessor.java | 8 ++++++-- .../ResteasyKeycloakAdminClientRecorder.java | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/extensions/keycloak-admin-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java b/extensions/keycloak-admin-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java index 5ac5f6fef3237..aa65258d906e4 100644 --- a/extensions/keycloak-admin-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java +++ b/extensions/keycloak-admin-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java @@ -13,6 +13,8 @@ import org.keycloak.json.StringOrArraySerializer; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.deployment.Capabilities; +import io.quarkus.deployment.Capability; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.ExecutionTime; @@ -49,8 +51,10 @@ ReflectiveClassBuildItem reflect() { @Record(ExecutionTime.STATIC_INIT) @Produce(ServiceStartBuildItem.class) @BuildStep - public void integrate(ResteasyKeycloakAdminClientRecorder recorder, TlsConfig tlsConfig) { - recorder.setClientProvider(tlsConfig.trustAll); + public void integrate(ResteasyKeycloakAdminClientRecorder recorder, TlsConfig tlsConfig, Capabilities capabilities) { + boolean areJSONBProvidersPresent = capabilities.isPresent(Capability.RESTEASY_JSON_JSONB) + || capabilities.isPresent(Capability.RESTEASY_JSON_JSONB_CLIENT); + recorder.setClientProvider(tlsConfig.trustAll, areJSONBProvidersPresent); } @Record(ExecutionTime.RUNTIME_INIT) diff --git a/extensions/keycloak-admin-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java b/extensions/keycloak-admin-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java index 75fb6d2924896..0ded9fe8b5307 100644 --- a/extensions/keycloak-admin-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java +++ b/extensions/keycloak-admin-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java @@ -6,7 +6,10 @@ import javax.net.ssl.SSLContext; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Produces; import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.MediaType; import org.keycloak.admin.client.ClientBuilderWrapper; import org.keycloak.admin.client.Keycloak; @@ -14,6 +17,7 @@ import org.keycloak.admin.client.spi.ResteasyClientClassicProvider; import io.quarkus.keycloak.admin.client.common.KeycloakAdminClientConfig; +import io.quarkus.resteasy.common.runtime.jackson.QuarkusJacksonSerializer; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; @@ -58,14 +62,25 @@ public Keycloak get() { }; } - public void setClientProvider(boolean tlsTrustAll) { + public void setClientProvider(boolean tlsTrustAll, boolean areJSONBProvidersPresent) { Keycloak.setClientProvider(new ResteasyClientClassicProvider() { @Override public Client newRestEasyClient(Object customJacksonProvider, SSLContext sslContext, boolean disableTrustManager) { // point here is to use default Quarkus providers rather than org.keycloak.admin.client.JacksonProvider // as it doesn't work properly in native mode - return ClientBuilderWrapper.create(sslContext, tlsTrustAll || disableTrustManager).build(); + var builder = ClientBuilderWrapper.create(sslContext, tlsTrustAll || disableTrustManager); + if (areJSONBProvidersPresent) { + // when both Jackson and JSONB providers are present, we need to ensure Jackson is used + builder.register(new AppJsonQuarkusJacksonSerializer(), 100); + } + return builder.build(); } }); } + + // makes media type more specific which ensures that it will be used first + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + static class AppJsonQuarkusJacksonSerializer extends QuarkusJacksonSerializer { + } }