How to load a class from module(.jmod) file at runtime?



I want to load classes from a module (.jmod) file at runtime into the application memory.

I know that we can easily load classes from a (.jar) file using 🙂

ClassLoader loader = URLClassLoader.newInstance(new URL[]{
                jarFile.toURL()
            });

The total code snippet can be found at this-repo in src omega.deassembler.JarLoader class

But the problem is URLClassLoader is unable to read the modules(.jmod).

So is there any other internal class or library to load classes from a module(.jmod) file.

Actually, I am creating an IDE and this-repo is a part of it for loading content-assist hints.

Earlier, I was using javap command to disassemble and load hints (see omegaide on github).

But this technique consumes much time, so i am writing it again!

Thank You.

Answer

This is not exactly the answer but a method to make URLClassLoader usable when it has to read modules.

Earlier URLClassLoader was throwing this exception when trying to read a module file(.jmod)

when omitting the module-info

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

and when including the meta-info

Exception in thread "main" java.lang.NoClassDefFoundError: classes/module-info is not a class because access_flag ACC_MODULE is set

This means that it is unable to identify the directory system inside the jmod file.

So as we know, that a simple jar file contains classes and resources only (Just exclude meta-info).

And in a module file(.jmod), all the classes are placed inside the classes folder and all the resources are placed in the resources folder.

Thus, We can create a temporary jar file say “modular-jar.jar” with the contents of classes and resources from the module file,

and then using standard URLClassLoader we can load it onto the classpath

and then can immediately delete the file.

This will just work at least in my case

Here’s the code snippet

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");
}


Source: stackoverflow