SpringBoot集成Keycloak Admin Client出现NoSuchMethodError问题求助
解决Keycloak Admin Client与JAX-RS/Jersey版本冲突导致的NoSuchMethodError问题
问题场景回顾
你在Spring Boot 1.5.3.RELEASE应用中使用Keycloak Admin Client 3.4.3.Final时,调用Response response = getInstance().realm(REALM).users().create(user);抛出了如下错误:
java.lang.NoSuchMethodError: javax.ws.rs.core.UriBuilder.resolveTemplates(Ljava/util/Map;)Ljavax/ws/rs/core/UriBuilder; at org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.resolveTemplates(ClientWebTarget.java:178) ~[resteasy-client-3.5.1.Final.jar:3.5.1.Final] at org.keycloak.admin.client.Keycloak.realm(Keycloak.java:118) ~[keycloak-admin-client-3.4.3.Final.jar:3.4.3.Final]
同时你的项目作为依赖库被其他项目引用,对方依赖Jersey 1.54,你尝试添加Jersey 2.0.2.RELEASE但问题未解决。
1. 问题根源是什么?是否是该模块版本的bug?
这不是Keycloak Admin Client的bug,核心原因是JAX-RS API版本不兼容导致的依赖冲突:
- Keycloak Admin Client 3.4.3.Final依赖的是JAX-RS 2.x规范,
UriBuilder.resolveTemplates(Map)是JAX-RS 2.0才新增的方法; - 你的项目中因其他依赖引入了Jersey 1.54(属于Jersey 1.x系列),而Jersey 1.x是基于JAX-RS 1.x规范实现的,其中的
UriBuilder类并没有这个新增方法; - 运行时JVM加载了旧版本的
UriBuilder类,导致Keycloak Admin Client调用不存在的方法,抛出NoSuchMethodError。
2. 遇到此类问题时,该如何排查并确定修改方向?
推荐按以下步骤排查:
- 生成依赖树,定位冲突源:执行Maven命令
mvn dependency:tree,搜索所有包含javax.ws.rs、jersey、resteasy的依赖项,找到哪个依赖路径引入了JAX-RS 1.x/Jersey 1.x的旧版本; - 对比依赖版本兼容性:确认Keycloak Admin Client的依赖要求(比如它依赖Resteasy 3.5.1.Final,这是JAX-RS 2.x的实现),确保项目中所有JAX-RS相关的API和实现都统一到2.x版本;
- 检查Spring Boot的默认依赖:Spring Boot 1.5.x可能会间接引入一些JAX-RS相关依赖,需要通过依赖树确认是否和Keycloak的依赖冲突。
3. 如何强制Maven使用指定版本的Jersey 2.x覆盖1.5.x版本?
因为你的项目是被其他项目引用的依赖库,需要通过Maven的依赖管理机制来强制锁定版本,具体操作如下:
方案1:通过<dependencyManagement>锁定版本
在你的POM中添加依赖管理块,强制指定所有Jersey相关依赖的版本为2.0.2.RELEASE,这样无论其他项目引入什么版本,都会优先使用你指定的版本:
<dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-client</artifactId> <version>2.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-common</artifactId> <version>2.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> <version>2.0.2.RELEASE</version> </dependency> <!-- 其他Jersey相关依赖都在这里锁定版本 --> </dependencies> </dependencyManagement>
方案2:排除旧版本依赖
在你的项目依赖中,主动排除所有Jersey 1.x的依赖,避免旧版本被引入:
比如Spring Boot starter-web如果间接引入了Jersey 1.x,就添加排除规则:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>1.5.3.RELEASE</version> <exclusions> <exclusion> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> </exclusion> <exclusion> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> </exclusion> <exclusion> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-multipart</artifactId> </exclusion> <!-- 所有Jersey 1.x的groupId都是com.sun.jersey,统一排除 --> </exclusions> </dependency>
额外提示:统一JAX-RS实现
Keycloak Admin Client本身依赖Resteasy(JAX-RS 2.x实现),如果你的项目不需要Jersey,也可以考虑完全排除Jersey依赖,改用Resteasy作为JAX-RS实现,这样能避免两种实现的冲突。
内容的提问来源于stack exchange,提问作者Gregor Sklorz
相关产品推荐
相关产品推荐

