Keycloak 12升级至26时自定义Provider遇类型转换错误求助
Keycloak 12升级至26版本自定义提供者适配错误修复
问题概述
将Keycloak从12版本升级到26版本并适配自定义提供者时,出现java.lang.VerifyError错误,核心原因是javax.ws.rs与jakarta.ws.rs的API冲突,同时Resteasy版本不兼容。
错误日志
2025-01-30 15:12:45,024 ERROR [org.keycloak.events.EventBuilder] (executor-thread-1) 向keycloak-provider发送类型失败:java.lang.VerifyError: 返回类型错误 Exception Details: Location: org/jboss/resteasy/core/providerfactory/Utils.createUriBuilder()Ljavax/ws/rs/core/UriBuilder; @7: areturn Reason: 当前栈帧stack[0]中的类型'org/jboss/resteasy/specimpl/ResteasyUriBuilderImpl'无法转换为方法签名中的'javax/ws/rs/core/UriBuilder' Current Frame: bci: @7 flags: { } locals: { } stack: { 'org/jboss/resteasy/specimpl/ResteasyUriBuilderImpl' } Bytecode: 0000000: bb00 2659 b700 27b0
完整堆栈跟踪
at org.jboss.resteasy.core.providerfactory.CommonProviders.processProviderContracts(CommonProviders.java:82) at org.jboss.resteasy.core.providerfactory.ClientHelper.processProviderContracts(ClientHelper.java:104) at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.processProviderContracts(ResteasyProviderFactoryImpl.java:841) at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.registerProvider(ResteasyProviderFactoryImpl.java:829) at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.registerProvider(ResteasyProviderFactoryImpl.java:816) at org.jboss.resteasy.plugins.providers.RegisterBuiltin.registerProviders(RegisterBuiltin.java:109) at org.jboss.resteasy.plugins.providers.RegisterBuiltin.register(RegisterBuiltin.java:74) at org.jboss.resteasy.plugins.providers.RegisterBuiltin.getClientInitializedResteasyProviderFactory(RegisterBuiltin.java:54) at org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl.getProviderFactory(ResteasyClientBuilderImpl.java:357) at org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl.build(ResteasyClientBuilderImpl.java:373) at provider.SSOGeneralFederationKCAuthorization.getToken(KCAuthorization.java:27) at provider.EventListenerProvider.asyncSearch(EventListenerProvider.java:97) at provider.EventListenerProvider.onEvent(EventListenerProvider.java:39) at org.keycloak.events.EventBuilder.sendNow(EventBuilder.java:262) at org.keycloak.events.EventBuilder.send(EventBuilder.java:249) at org.keycloak.events.EventBuilder.success(EventBuilder.java:217) at org.keycloak.authentication.forms.RegistrationUserCreation.success(RegistrationUserCreation.java:174) at org.keycloak.authentication.FormAuthenticationFlow.processAction(FormAuthenticationFlow.java:253) at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:128) at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:1034) at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:378) at org.keycloak.services.resources.LoginActionsService.processRegistration(LoginActionsService.java:747) at org.keycloak.services.resources.LoginActionsService.registerRequest(LoginActionsService.java:811) at org.keycloak.services.resources.LoginActionsService.processRegister(LoginActionsService.java:789) at org.keycloak.services.resources.LoginActionsService$quarkusrestinvoker$processRegister_7a9f3962753907b18ff9c85418d7f9feed84dedc.invoke(Unknown Source) at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29) at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141) at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147) at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:635) at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516) at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:842)
引发问题的方法
public static String getToken() { Keycloak keycloak = KeycloakBuilder .builder() .serverUrl(propertiesService.getProperty(URL_KEYCLOAK_SERVER)) .realm(REALM_MASTER) .username(USERNAME_ADMIN) .password(PASSWORD_ADMIN) .clientId(CLIENT_ADMIN) .resteasyClient(new ResteasyClientBuilderImpl().connectionPoolSize(10).build()) .build(); return keycloak.tokenManager().getAccessTokenString(); }
当前pom.xml依赖
<dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-core</artifactId> <version>26.0.3</version> <exclusions> <exclusion> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-admin-client</artifactId> <version>26.0.4</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> <version>6.2.11.Final</version> <exclusions> <exclusion> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-core</artifactId> <version>4.7.9.Final</version> <exclusions> <exclusion> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> </exclusion> </exclusions> </dependency>
providers文件夹中的额外JAR包
jakarta.ws.rs-api-4.0.0.jarjavax.ws.rs-api-2.1.1.jarjson-20240303.jarkeycloak-admin-client-26.0.4.jarresteasy-client-6.2.11.Final.jarresteasy-core-4.7.9.Final.jarresteasy-jackson2-provider-4.7.9.Final.jarresteasy-multipart-provider-6.2.11.Final.jarwildfly-client-config-1.0.1.Final.jar
修复方案
1. 核心问题分析
Keycloak 17+版本基于Quarkus,全面切换到Jakarta EE规范,不再兼容javax.ws.rs相关API。你的问题源于:
- 混用
javax.ws.rs和jakarta.ws.rs的API包,导致类加载冲突 - Resteasy版本不兼容:4.x对应javax,6.x对应jakarta,同时引入两个版本引发类型转换错误
- 手动添加的JAR包与依赖管理的包重复,加剧冲突
2. 步骤1:清理pom.xml依赖
修改后的pom.xml如下,统一依赖版本并移除冲突项:
<dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-core</artifactId> <version>26.0.4</version> <!-- 与admin-client版本保持一致 --> <exclusions> <exclusion> <groupId>*</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-admin-client</artifactId> <version>26.0.4</version> <!-- 自动引入兼容的Resteasy和Jakarta依赖,无需手动添加 --> </dependency>
说明:
- 移除所有手动添加的
resteasy-client、resteasy-core、jakarta.ws.rs-api依赖,由keycloak-admin-client自动引入匹配版本 - 确保
keycloak-core和keycloak-admin-client版本完全一致 - 排除所有不必要的传递依赖,避免冲突
3. 步骤2:清理providers文件夹中的冲突JAR
删除以下JAR包:
javax.ws.rs-api-2.1.1.jar(完全废弃,改用Jakarta)jakarta.ws.rs-api-4.0.0.jar(版本过高,Keycloak 26对应Jakarta EE 10,适配3.1.x版本)resteasy-core-4.7.9.Final.jar(与Resteasy 6.x冲突)keycloak-admin-client-26.0.4.jar(由pom依赖管理,无需手动放置)resteasy-jackson2-provider-4.7.9.Final.jar(版本不兼容,改用admin-client传递的版本)
保留必要的JAR:
json-20240303.jarresteasy-client-6.2.11.Final.jarresteasy-multipart-provider-6.2.11.Final.jarwildfly-client-config-1.0.1.Final.jar
4. 步骤3:修正代码中的客户端创建逻辑
不要直接实例化ResteasyClientBuilderImpl,改用兼容Jakarta的API:
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; public static String getToken() { // 使用ResteasyClientBuilder而非Impl类 ResteasyClient client = new ResteasyClientBuilder() .connectionPoolSize(10) .build(); Keycloak keycloak = KeycloakBuilder .builder() .serverUrl(propertiesService.getProperty(URL_KEYCLOAK_SERVER)) .realm(REALM_MASTER) .username(USERNAME_ADMIN) .password(PASSWORD_ADMIN) .clientId(CLIENT_ADMIN) .resteasyClient(client) .build(); return keycloak.tokenManager().getAccessTokenString(); }
或者更简单,直接使用Keycloak默认客户端(无需手动创建):
public static String getToken() { Keycloak keycloak = KeycloakBuilder .builder() .serverUrl(propertiesService.getProperty(URL_KEYCLOAK_SERVER)) .realm(REALM_MASTER) .username(USERNAME_ADMIN) .password(PASSWORD_ADMIN) .clientId(CLIENT_ADMIN) .build(); return keycloak.tokenManager().getAccessTokenString(); }
5. 步骤4:重新构建并部署
- 执行
mvn clean install清理旧依赖并重新构建 - 将新的提供者JAR部署到Keycloak的
providers文件夹 - 重启Keycloak服务
内容的提问来源于stack exchange,提问作者lala
相关产品推荐
相关产品推荐

