问题描述
我想在运行时将模块 (.jmod) 文件中的类加载到应用程序内存中。
我知道我们可以使用 :-) 轻松地从 (.jar) 文件加载类
ClassLoader loader = urlclassloader.newInstance(new URL[]{
jarFile.toURL()
});
可以在 src omega.deassembler.JarLoader 类中的 this-repo 找到全部代码片段
但问题是 urlclassloader 无法读取模块(.jmod)。
是否还有其他内部类或库可以从模块 (.jmod) 文件中加载类。
实际上,我正在创建一个 IDE,而 this-repo 是其中的一部分,用于加载内容辅助提示。
之前,我使用 javap 命令来反汇编和加载提示(请参阅 omegaide on github)。
但是这个技巧很耗时间,所以我再写一遍!
谢谢。
解决方法
这不完全是答案,而是一种使 URLClassLoader
在必须读取模块时可用的方法。
之前的 URLClassLoader 在尝试读取模块文件 (.jmod) 时抛出此异常
当省略模块信息
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/javafx/event/DirectEvent (wrong name: classes/com/sun/javafx/event/DirectEvent)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1010)
etc
当包括元信息
Exception in thread "main" java.lang.NoClassDefFoundError: classes/module-info is not a class because access_flag ACC_MODULE is set
这意味着无法识别jmod文件内的目录系统。
据我们所知,一个简单的 jar 文件仅包含类和资源(仅排除元信息)。
在一个模块文件 (.jmod) 中,所有类都放在 classes 文件夹中,所有资源都放在 resources 文件夹中。
因此,我们可以使用模块文件中的类和资源的内容创建一个临时 jar 文件,例如“modular-jar.jar”,
然后使用标准的 URLClassLoader 我们可以将它加载到类路径中
然后可以立即删除文件。
这至少在我的情况下有效
这是代码片段
public static synchronized JarLoader prepareModule(String modulePath){
try{
ZipFile moduleFile = new ZipFile(modulePath);
ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream("readable-module-data.jar"));
for(Enumeration enums = moduleFile.entries(); enums.hasMoreElements();){
ZipEntry entry = (ZipEntry)enums.nextElement();
String name = entry.getName();
if((name.startsWith("classes") && !name.contains("module-info")) || name.startsWith("resources")){
zipOutputStream.putNextEntry(new ZipEntry(name.substring(name.indexOf('/') + 1)));
InputStream in = moduleFile.getInputStream(entry);
while(in.available() > 0)
zipOutputStream.write(in.read());
zipOutputStream.flush();
}
}
zipOutputStream.close();
}
catch(Exception e){
e.printStackTrace();
}
return new JarLoader("readable-module-data.jar");
}