如何强制从指定Jar包导入同包同名的Java标准类?
如何实现以下假想语法的等效效果:
import plugin.jar.netscape.javascript.JSObject; // 从plugin.jar导入netscape.javascript.JSObject
我需要使用Java类库中的指定类:
- 包名:
netscape.javascript - 类名:
netscape.javascript.JSObject - 实现说明:对应Oracle Java Plugin 2 LiveConnect组件提供的版本,核心方法包含
getWindow(java.applet.Applet)
常规场景下,只需要编写如下导入语句即可完成类引入:
import netscape.javascript.JSObject;
问题背景:JSObject存在多个实现版本
Java类加载机制存在同名类冲突场景:当前环境下存在另一个JSObject实现,包名、类名和上述类完全一致,属于JavaFX运行时自带的实现。
两个实现的对应关系如下:
| 所属Jar包 | 包名 | 全限定类名 |
|---|---|---|
| plugin.jar | netscape.javascript | netscape.javascript.JSObject |
| jfxrt.jar | netscape.javascript | netscape.javascript.JSObject |
即当前类路径下同时存在两个netscape.javascript.JSObject实现:
- 实现1:
plugin.jar包内的netscape/javascript/JSObject - 实现2:
jfxrt.jar包内的netscape/javascript/JSObject
正常情况下Java内置类加载机制允许不同Jar包导出同包同名类,默认不会主动抛出冲突错误。
版本Bug说明
问题在于jfxrt.jar(JavaFX运行时)中的实现2存在多处已知Bug,多个核心方法未完成实现,相关问题多数被官方标记为不予修复。
我需要在当前.java文件中强制使用无Bug的实现1版本的JSObject,但Java本身不支持如下指定Jar包来源的导入语法:
import plugin.jar.netscape.javascript.JSobject
注意:直接从项目全局排除jfxrt.jar的方案不可行,项目中其他业务代码依赖JavaFX的实现2版本,不能全局移除该依赖。
已尝试的排查工作
我曾删除本机所有能找到的jfxrt.jar副本,该操作直接导致SmartSVN、Minecraft、Aqua Data Studio、便携版SmartSVN、Java 1.8环境损坏,但即使如此,Java编译器仍然能加载到存在Bug的JSObject版本。
我尝试通过IDE的查看定义功能跳转JSObject类源码,编译器从某个未知位置加载到了确实存在Bug的源码文件:
我还使用Process Monitor监控所有包含以下关键词的文件访问记录:
- jfxrt.jar
- jfxrt
- JSObject
- netscape
尝试定位Bug版JSObject的加载来源,但没有找到对应文件访问记录。推测Java运行时没有将类拆分为数百个独立Jar包,而是将相关类整合到了更大的分发包中。
核心诉求:
- 当Java类路径存在两个同包同名类的竞争实现时
- 如何强制导入指定来源Jar包的实现版本
- 而不是让Java默认的类加载机制自动加载类路径搜索顺序中靠前的版本?
在Visual Studio Code中按F12查看内置类声明时,IDE是从哪个路径加载对应源码的?如果能定位源码路径,有助于后续提出更精准的问题。
参考阅读
- Why is getWindow() not able to be resolved?
- Not able to resolve JSObject in a java applet project
- JSObject.getWindow(this); always throws an exception
- Not able to resolve JSObject in a java applet project(高赞回答)
临时规避方案
目前只能通过放弃功能的方式临时规避问题:
/* * Java存在已知缺陷:classpath下存在两个netscape.javascript.JSObject实现: * - plugin.jar/netscape.javascript.JSObject * - jfxrt.jar/netscape.javascript.JSObject * * 第二个实现存在标记为WONTFIX的已知Bug * * 我们需要强制使用plugin.jar中的实现,但Java本身没有提供指定Jar包来源导入类的语法 * 目前没有其他可行方案,只能暂时不使用该功能 */ private JSObject jsWindow; // jsWindow = JSObject.getWindow(this); jsWindow = null; // 希望这个功能不是核心必需的
内容的提问来源于stack exchange,提问作者Ian Boyd

