Java 20中调用JDBI.open获取SqlObject Dao实例报错求助
问题原因分析
报错的核心是Java模块系统的访问限制:JDBI 2.x版本依赖的cglib库使用反射调用java.lang.ClassLoader.defineClass方法,但Java 20的模块系统默认不允许未命名模块(你的应用代码和依赖库所在的模块)访问java.lang包的内部方法,导致InaccessibleObjectException。
JDBI 2.78是2017年的旧版本,其依赖的cglib版本未适配Java 9及以上的模块系统,因此在Java 20中无法正常生成SqlObject代理类。
解决方案
方案1:升级到JDBI 3.x(推荐)
JDBI 3.x彻底替换了cglib为ByteBuddy,完全兼容Java 9+的模块系统,同时提供更多新特性和长期支持。
步骤1:更新pom.xml依赖
替换原JDBI依赖为3.x版本:
<dependency> <groupId>org.jdbi.v3</groupId> <artifactId>jdbi3-core</artifactId> <version>3.38.1</version> <!-- 可替换为最新稳定版 --> </dependency> <dependency> <groupId>org.jdbi.v3</groupId> <artifactId>jdbi3-sqlobject</artifactId> <version>3.38.1</version> </dependency>
步骤2:调整代码中的导入路径
JDBI 3.x的包名从org.skife.jdbi.v2改为org.jdbi.v3,需要更新相关导入:
// 替换原DBI导入 import org.jdbi.v3.core.DBI; // 替换Dao注解导入 import org.jdbi.v3.sqlobject.statement.SqlQuery; import org.jdbi.v3.sqlobject.result.SingleValueResult;
步骤3:验证代码逻辑
JDBI 3.x的open方法用法基本兼容,但推荐使用更优雅的资源管理方式:
try (MyDao myDao = dbi.onDemand(MyDao.class)) { int id = myDao.getObjectId(); System.out.println("got id:" + id); }
(onDemand方法会自动管理连接生命周期,比open更简洁)
方案2:添加JVM启动参数(临时 workaround)
如果暂时无法升级JDBI,可以通过JVM参数放宽模块系统限制,允许未命名模块访问java.lang包:
--add-opens java.base/java.lang=ALL-UNNAMED
在IDE中配置:
- IntelliJ IDEA:Run Configuration → VM options中添加上述参数
- Eclipse:Run Configurations → Arguments → VM arguments中添加
命令行运行:
java --add-opens java.base/java.lang=ALL-UNNAMED -jar your-application.jar
⚠️ 注意:此方案仅作为临时解决办法,不推荐用于生产环境,因为它绕过了Java模块系统的安全限制。
内容的提问来源于stack exchange,提问作者slayton
相关产品推荐
相关产品推荐

