非模块化依赖在Java 9+中形成“可见性黑洞”,根源是模块系统拒绝建立可读性与可访问性契约;解决关键是补全module-info.java,而非绕过规则。

非模块化依赖在 Java 9+ 模块系统中会形成“可见性黑洞”——类存在、路径可达,但编译期无法引用、运行时反射失败、jlink 打包报错。根源不是类找不到,而是模块系统拒绝建立可读性(readability)和可访问性(accessibility)契约。解决关键在于补全缺失的模块语义,而非绕过规则。
识别自动模块的隐式行为
未含 module-info.class 的 JAR(如 hutool、commons-lang3)会被 JVM 当作“自动模块”加载,其名称由 JAR 文件名推导(如 hutool-core-5.8.29.jar → 模块名 hutool.core)。这种命名不稳定且不支持 exports 或 opens,导致:
- 其他命名模块无法通过
requires显式声明依赖 - 即使加了
--add-modules ALL-SYSTEM,也无法导出包供编译期使用 - Jackson 等框架反射访问内部类时抛
InaccessibleObjectException
用 jdeps 生成基础 module-info.java
对非模块化 JAR 主动补全描述符是最可控的方案。进入空目录,执行:
jdeps --ignore-missing-deps --generate-module-info . hutool-core-5.8.29.jar
立即学习“Java免费学习笔记(深入)”;
该命令会在当前目录生成 hutool.core/module-info.java,内容类似:
module hutool.core {
exports cn.hutool.core.util;
exports cn.hutool.core.date;
// 自动分析出的最小导出集
}
注意:需手动检查并补充 opens(如需反射序列化),例如添加:opens cn.hutool.core.bean to com.fasterxml.jackson.databind;
在主模块中正确声明依赖与开放策略
你的业务模块 com.example.app 不能只写 requires hutool.core; 就完事。必须配合使用:
-
显式 requires:确保模块图连通,避免启动时报
Module not found -
必要 exports/opens:若你自己的模块要向外部暴露基于 hutool 的 API,需导出对应包;若框架需反射你的模型类,且模型用了 hutool 工具类,可能还需
opens你自己的包给 Jackson -
transitive 传递依赖:当 hutool.core 被多个子模块共用,可在聚合模块中声明
requires transitive hutool.core;,避免下游重复声明
打包与运行时兜底策略
若暂无法补全所有依赖的 module-info,可用以下组合降低风险:
- 构建时加
--add-modules hutool.core,com.fasterxml.jackson.databind显式激活自动模块 - 运行时加
--illegal-access=permit(仅限 Java 16 前)或更安全的--add-opens java.base/java.lang=ALL-UNNAMED开放特定包 - jlink 打包时用
--add-modules ALL-MODULE-PATH强制包含 classpath 中所有自动模块
这些是临时手段,长期仍应推动依赖方模块化或自行维护轻量 module-info 补丁。



















