如何在运行时从模块.jmod文件加载类?

问题描述

我想在运行时将模块 (.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");
}