如何在运行时从模块(.jmod)文件加载 class?
How to load a class from module(.jmod) file at runtime?
我想在运行时将 classes 从模块 (.jmod) 文件加载到应用程序内存中。
我知道我们可以使用 :-)
从 (.jar) 文件轻松加载 classes
ClassLoader loader = URLClassLoader.newInstance(new URL[]{
jarFile.toURL()
});
完整的代码片段可以在 src this-repo 找到 omega.deassembler.JarLoader class
但问题是 URLClassLoader 无法读取模块 (.jmod)。
那么是否有任何其他内部 class 或库可以从模块 (.jmod) 文件加载 classes。
实际上,我正在创建一个 IDE,这个存储库是其中的一部分,用于加载内容辅助提示。
早些时候,我使用 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)中,所有的类都放在类文件夹中,所有的资源都放在资源 文件夹。
因此,我们可以创建一个临时 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");
}
我想在运行时将 classes 从模块 (.jmod) 文件加载到应用程序内存中。
我知道我们可以使用 :-)
从 (.jar) 文件轻松加载 classesClassLoader loader = URLClassLoader.newInstance(new URL[]{
jarFile.toURL()
});
完整的代码片段可以在 src this-repo 找到 omega.deassembler.JarLoader class
但问题是 URLClassLoader 无法读取模块 (.jmod)。
那么是否有任何其他内部 class 或库可以从模块 (.jmod) 文件加载 classes。
实际上,我正在创建一个 IDE,这个存储库是其中的一部分,用于加载内容辅助提示。
早些时候,我使用 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)中,所有的类都放在类文件夹中,所有的资源都放在资源 文件夹。
因此,我们可以创建一个临时 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");
}