Java 17环境下Quarkus集成OptaPlanner时参数化单元测试正常运行但热重载失效的配置方案咨询
最近把JDK升级到17后,在Quarkus项目里跑OptaPlanner的参数化单元测试时踩了个坑:
一开始直接抛出InaccessibleObjectException,提示模块java.base没把java.util开放给未命名模块,导致XStream的TreeSetConverter初始化失败,参数化测试全挂。
我一开始把--add-opens相关参数一股脑加到了quarkus-maven-plugin的compilerArgs、jvmArgs,还有maven-surefire-plugin、native环境的maven-failsafe-plugin的argLine里,结果参数化测试能正常跑了,但Quarkus的热重载功能直接失效了——修改代码后重启Quarkus时,居然报invalid flag错误,把我整懵了。
问题根源
后来才搞明白:--add-opens和--enable-preview是JVM运行时参数,不是Java编译器的参数!我之前把这些参数塞到了quarkus-maven-plugin的compilerArgs里,而compilerArgs是给javac编译器用的,编译器根本不认这些JVM启动参数,热重载时Quarkus会调用编译器,自然就报错了。
解决配置方案
核心思路就是拆分参数类型:编译器参数只放编译相关的,JVM运行参数只放在JVM启动相关的配置节点里。
1. 调整Quarkus Maven插件配置
把compilerArgs里的--add-opens参数全部移除,只保留编译需要的参数(比如--enable-preview,如果你的项目用了Java预览特性的话),jvmArgs里保留所有JVM运行时需要的参数:
<plugin> <groupId>${quarkus.platform.group-id}</groupId> <artifactId>quarkus-maven-plugin</artifactId> <version>${quarkus.platform.version}</version> <extensions>true</extensions> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> <!-- 编译器参数只保留编译相关的,移除所有--add-opens --> <compilerArgs> <arg>--enable-preview</arg> </compilerArgs> <!-- JVM运行参数保留所有需要的--add-opens和--enable-preview --> <jvmArgs>--enable-preview --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED</jvmArgs> </configuration> <executions> <execution> <goals> <goal>build</goal> <goal>generate-code</goal> <goal>generate-code-tests</goal> </goals> </execution> </executions> </plugin>
2. 保留测试插件的参数配置
maven-surefire-plugin和native环境的maven-failsafe-plugin的argLine配置不变,因为这些是给测试运行时的JVM用的,没问题:
<!-- maven-surefire-plugin 配置 --> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>${surefire-plugin.version}</version> <configuration> <argLine> --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED </argLine> <systemPropertyVariables> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> <maven.home>${maven.home}</maven.home> </systemPropertyVariables> </configuration> </plugin> <!-- Native Profile 里的 maven-failsafe-plugin 配置 --> <profiles> <profile> <id>native</id> <activation> <property> <name>native</name> </property> </activation> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>${surefire-plugin.version}</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> <configuration> <argLine> --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED </argLine> <systemPropertyVariables> <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> <maven.home>${maven.home}</maven.home> </systemPropertyVariables> </configuration> </execution> </executions> </plugin> </plugins> </build> <properties> <quarkus.package.type>native</quarkus.package.type> </properties> </profile> </profiles>
3. 额外说明
如果你的项目没有用到Java预览特性,可以直接把--enable-preview参数从所有配置里移除,进一步简化配置。
效果验证
调整完配置后:
- OptaPlanner的参数化单元测试可以正常运行,反射权限问题解决;
- Quarkus的热重载功能恢复正常,修改代码后重启不再报无效flag错误;
- 非参数化的简单测试依然不需要额外配置就能正常工作。
内容的提问来源于stack exchange,提问作者minioim

