Java 17 迁移后 ADF 在 WebLogic 14.1.2 中出现模块包冲突
这类错误表明 Java 模块系统(JPMS)发现了包来源冲突:某个模块同时读取了两个包含同名包的模块。删除重复版本的 JAR 不一定能解决问题,因为两个不同的 JAR 即使没有重复类,也可能包含同一个包。
应先确认 JDeveloper 是否将 ADF 和其他传统依赖放到了 module-path,再核对 ADF 库的来源和版本。仅凭现有信息,还无法确定应该删除哪个 ADF JAR,也无法确认当前 ADF、JDeveloper、WebLogic 与 JDK 的具体组合是否受支持。
如何理解这些报错
以这条错误为例:
module commons.validator reads package oracle.adf.share.security.policystore from both adf.share.support and adf.share.security
在当前解析出的模块关系中,commons.validator 同时读取了 adf.share.support 和 adf.share.security,而后两个模块都提供了 oracle.adf.share.security.policystore 包。
报错中出现 commons.validator,并不意味着需要修改 Commons Validator。应检查提供冲突包的两个模块,以及它们为什么进入了同一个模块图。
另外两条错误分别涉及:
javax.naming:外部jndi模块与 JDK 的java.naming模块冲突。org.w3c.dom:外部xalan模块与 JDK 的java.xml模块冲突。
包冲突与同一个库加载了两个版本并不完全相同。即使每个依赖都只有一个版本,不同库之间仍可能包含同名包。
先确定错误发生在哪个阶段
从日志中确认错误发生在 JDeveloper 的编辑器检查、编译、部署,还是 WebLogic 启动应用时。然后查看对应阶段的实际参数,重点查找:
--module-path
-p
--class-path
-classpath
-cp
--add-modules
同时检查项目是否存在 module-info.java,以及 JDeveloper 的项目依赖、编译器选项和运行配置中是否启用了模块相关设置。具体界面位置取决于 JDeveloper 版本,应以实际生成的参数为准。
即使应用没有 module-info.java,放在 module-path 上的普通 JAR 也可能被识别为 automatic module。因此,清理 classpath 后仍然报错,不能证明 module-path 已经没有冲突。
找到模块对应的实际 JAR
使用 Java 17 的 jar 工具检查候选文件。以下路径是占位示例,需要替换成项目实际使用的文件:
jar --describe-module --file /path/to/library.jar
jar --list --file /path/to/library.jar
第一条命令用于查看模块描述或派生的 automatic module 信息;第二条用于查看 JAR 内容。能够派生出模块名称,不代表该 JAR 在当前构建中一定通过 module-path 加载,仍需结合构建参数判断。
针对 ADF 错误,分别检查两个候选 JAR 是否包含以下目录下的类:
oracle/adf/share/security/policystore/
其他错误也应按完整包名逐项检查。不同子包是不同的包,不能仅凭两个 JAR 都含有 oracle/adf/share/ 目录就判定它们冲突。
记录每个冲突 JAR 的完整路径,特别留意它是否来自:
- JDeveloper 或 ADF 安装目录中的库定义。
- 项目手工维护的依赖目录。
- 已导入的其他项目或共享库。
- EAR、WAR 或部署配置额外引入的依赖。
删除项目目录中的一个文件后,IDE 库定义或其他路径仍可能引用另一份文件。
根据应用是否需要 JPMS 调整配置
如果应用继续采用传统 classpath 构建和部署,且工具链支持这种方式,可以将误放到 module-path 上的传统依赖恢复到 classpath。对于同名包分布在多个 JAR 中的旧库,应优先检查这方面的配置。
下面仅演示两类参数的区别,不是完整的 ADF 构建命令:
# 通过 module-path 解析依赖
javac --module-path "lib" ...
# 通过传统 classpath 查找依赖
javac -classpath "lib/*" ...
classpath 不施加相同的 JPMS 包解析约束,但重复类仍可能造成类加载顺序问题,因此仍需清理实际重复的依赖。
如果应用必须作为命名模块构建,就需要从依赖组合上消除冲突,例如采用不再拆分同名包的兼容库组合。仅修改 requires 或模块名称,不能消除两个被读取模块都包含同一个包的问题。
核对 ADF 库的版本与部署来源
如果 ADF 内部包仍然冲突,应重点检查是否混用了不同安装目录、不同发布版本或不同补丁级别的库。
建议按以下顺序处理:
- 记录实际使用的 JDeveloper、ADF Runtime、WebLogic 和 JDK 的完整版本及补丁信息。
- 核对该组合的官方认证信息和部署要求。WebLogic 的 JDK 支持情况不能单独证明整套 ADF 开发及运行环境兼容。
- 根据对应版本的 ADF 库定义和部署要求,整理项目依赖,清除旧环境残留的手工引用。
- 检查 EAR/WAR 中的内容,确认需要由服务器或共享库提供的依赖是否又被应用重复打包。具体保留位置应遵循所用版本的部署要求。
- 修正依赖配置后,清理构建输出和缓存,再重新构建。
不要仅凭模块名称就删除 adf.share.support 或 adf.share.security 对应的文件。它们可能各自包含应用需要的类;删除其中一个可能消除当前错误,却会引入后续的缺类问题。
哪些做法不能直接解决问题
--add-reads、--add-exports 和 --add-opens 分别用于调整可读性、导出或反射访问,不能直接消除这里的同名包冲突。
如果错误发生在编译阶段,调整 WebLogic 的应用类加载优先级也无法修复编译器的模块解析错误。应先解决产生错误的那个阶段,再检查部署后的类加载情况。
下一步应取得首次报错阶段的完整参数,以及两个冲突 ADF 模块对应的 JAR 完整路径。这些信息有助于区分问题是出在 module-path 配置、ADF 库混用,还是依赖本身不适合当前的模块化构建方式。
备注:内容仅供参考。
