
JDK 17 默认禁止反射访问核心模块(如 java.base)的内部成员,而 Rest Assured 依赖的 Groovy 运行时会主动调用 setAccessible(true) 遍历类构造器(包括 String(char[],int,int,Void)),触发 InaccessibleObjectException,导致 ExceptionInInitializerError。本文提供可落地的兼容方案。
jdk 17 默认禁止反射访问核心模块(如 `java.base`)的内部成员,而 rest assured 依赖的 groovy 运行时会主动调用 `setaccessible(true)` 遍历类构造器(包括 `string(char[],int,int,void)`),触发 `inaccessibleobjectexception`,导致 `exceptionininitializererror`。本文提供可落地的兼容方案。
Rest Assured 是基于 Groovy 构建的 Java REST 测试库,其底层高度依赖 Groovy 的动态元编程能力——尤其是对类构造器、字段和方法的反射式访问。而 JDK 17 强化了模块系统安全性,默认拒绝未显式授权的深层反射操作(即 --illegal-access=deny 已成为默认行为)。当 Groovy 初始化 String 等核心类的 MetaClass 时,会尝试缓存所有构造器(包括 JDK 内部私有构造器),并调用 Constructor.setAccessible(true)。由于 java.base/java.lang.String 并未向 unnamed module(即你的测试类路径)开放 java.lang 包,JVM 直接抛出:
java.lang.reflect.InaccessibleObjectException: Unable to make java.lang.String(char[],int,int,java.lang.Void) accessible: module java.base does not "opens java.lang" to unnamed module @3cda1055
这并非 Rest Assured 代码本身有误(如 RestAssured.baseURI = ... 完全合法),而是其依赖的 Groovy 运行时在 JDK 17 下的固有兼容性瓶颈。
✅ 推荐解决方案:JVM 启动参数 + 版本升级组合策略
1. 添加必需的 --add-opens 参数(立即生效)
在运行测试的 JVM 中添加以下参数(适用于 Maven Surefire、IDE 或命令行):
--add-opens java.base/java.lang=ALL-UNNAMED \ --add-opens java.base/java.util=ALL-UNNAMED \ --add-opens java.base/java.net=ALL-UNNAMED \ --add-opens java.base/java.time=ALL-UNNAMED \ --add-opens java.base/java.nio=ALL-UNNAMED
? 说明:Groovy 在初始化元类时会批量扫描常用 JDK 类(如 String, ArrayList, URL, LocalDateTime, ByteBuffer 等)的构造器。上述参数覆盖了绝大多数高频触发包。若仍有异常,根据堆栈中 opens XXX to YYY 提示追加对应包即可。
Maven Surefire 插件配置示例:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/java.time=ALL-UNNAMED
--add-opens java.base/java.nio=ALL-UNNAMED
</argLine>
</configuration>
</plugin>2. 升级 Rest Assured 至 5.3.0+(根本性缓解)
Rest Assured 5.3.0(2023年发布)起已将 Groovy 依赖从 3.0.x 升级至 4.0.15+,后者针对 JDK 17+ 做了关键优化:
- 减少对 String 等敏感内部构造器的预扫描;
- 改进 CachedClass 初始化逻辑,避免无谓的 setAccessible 调用;
- 与 JDK 17–21 的模块系统兼容性经过全面验证。
✅ 强烈建议升级:
<!-- Maven --> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>5.4.0</version> <!-- 当前最新稳定版 --> <scope>test</scope> </dependency>
⚠️ 注意:Rest Assured 4.x 仍基于 Groovy 3.x,无法彻底规避该问题;必须升级到 5.3.0+ 才能获得官方 JDK 17 兼容保障。
3. 替代方案(仅限受限场景)
若因组织策略无法升级 Rest Assured,或需临时绕过:
- 禁用 Groovy 元编程(不推荐):通过 -Dgroovy.use.classvalue=false 启动参数强制 Groovy 回退旧机制(可能引发其他兼容性问题,且非长期方案);
- 改用纯 Java 替代方案:如 HttpClient + Jackson 手动构建请求/解析响应,牺牲语法简洁性换取完全可控性(适合对稳定性要求极高的核心测试套件)。
? 关键注意事项
- --add-opens 是 JVM 级别参数,必须作用于测试执行进程(如 Surefire、JUnit Platform Launcher、IDE 的 Run Configuration),而非编译阶段;
- 不要使用 --illegal-access=permit(JDK 17 已废弃,且不解决根本问题);
- 避免过度开放(如 --add-opens java.base/ALL-UNNAMED=ALL-UNNAMED),仅按需开放必要包,符合最小权限原则;
- 若使用 Spring Boot Test,需同时为 spring-boot-maven-plugin 和 maven-surefire-plugin 配置相同参数;
- 持续集成(CI)环境中,确保所有构建节点的 JVM 启动脚本包含上述参数。
✅ 总结
JDK 17 下 Rest Assured 启动失败的本质,是 Groovy 动态特性与 JDK 模块安全模型的冲突。最稳妥的实践是“双管齐下”:立即添加精准的 --add-opens 参数保证当前测试通过,并尽快将 Rest Assured 升级至 5.3.0 或更高版本。此举不仅解决 JDK 17 兼容性,也为后续平滑迁移至 JDK 21+ 奠定基础。切勿尝试修改 Rest Assured 源码或降级 JDK——前者违背维护性原则,后者违反组织技术策略。










