Spring Boot调用ResponseEntity.getStatusCode()出现NoSuchMethodError问题排查
1. Servlet API 包名迁移导致类不兼容
Spring Boot 3.0.x 基于 Jakarta EE 9,所有 Servlet 相关 API 包从 javax.servlet 迁移至 jakarta.servlet。你的自定义库基于 Spring Boot 2.6.7(依赖 Java EE 8),编译时绑定的是 javax.servlet.http.HttpServletResponse。
运行时,传入自定义库的 response 实际是 jakarta.servlet.http.HttpServletResponse 实例(来自主应用的 Spring Boot 3.x 依赖)。尽管两个类都有 getStatusCode() 方法,但由于类的全限定名不同,JVM 判定为完全不同的类,自定义库编译时依赖的 javax.servlet.HttpServletResponse.getStatusCode() 方法在运行时实例上不存在,从而抛出 NoSuchMethodError。
2. 依赖版本冲突引发类加载异常
主应用依赖 Spring Boot 3.0.3,自定义库依赖 Spring Boot 2.6.7,导致类路径同时存在:
javax.servlet-api(自定义库的传递依赖)jakarta.servlet-api(主应用的依赖)
Spring Boot 3.x 类加载机制优先加载 jakarta.servlet 下的类,但自定义库代码是针对 javax.servlet 编译的,方法调用无法匹配运行时类,触发错误。
3. 调试可见返回值的原因
IntelliJ 调试器直接读取运行时对象的实际类型(jakarta.servlet.http.HttpServletResponse),展示该类的方法与返回值,不受自定义库编译时依赖类的限制,因此能看到返回值,但代码执行时仍会因类不兼容抛出异常。
- 升级自定义库至 Spring Boot 3.x:这是最彻底的方案,将自定义库的
spring-boot-starter-web版本升级到 3.0.x,同步迁移至jakarta.servletAPI,确保与主应用依赖一致。 - 排除自定义库的 Servlet API 依赖:若暂时无法升级,在主应用的构建文件(
pom.xml/build.gradle)中排除自定义库传递引入的javax.servlet-api,强制使用主应用的jakarta.servlet-api,但需注意这可能引发其他兼容性问题,需充分测试。 - 适配方法调用逻辑:修改自定义库中
getStatusCode()的调用方式,比如通过反射调用,或使用 Spring 提供的统一工具类获取状态码,兼容两个版本的 API。
内容的提问来源于stack exchange,提问作者akaliza

