Search code examples
javalinuxwindowsjarclassloader

How to reflect classes from JAR on windows


Assuming the following loader definition (the example is written in scala but it is almost the same as Java, thus you should easily understand the problem):

jar = new File("path/to/myjar.jar")
url = jar.toURI.toURL
urls = Array[URL](url)  // just a single-element array containing the url
loader = new URLClassLoader(urls)

The JAR myjar.jar contains org/pack/Simple.class. The Simple has standard package org.pack and was compiled and packed into the JAR via JavaCompiler. The JAR is correct (executable etc.)

On linux, loader.loadClass("org.pack.Simple") returns the correct Class object.

On windows, it throws a ClassNotFoundException. Of course, I use \ instead of / as a file separator.

What do I do wrong? Or does simply windows suck? I installed OracleJDK8 and added its bin/ folder to the path.

EDIT1:

If I unpack JAR into some directory and let the ClassLoader to read from URL pointing at that directory, everything works. How is this possible?


Solution

  • I struggled long with this problem yesterday, but after a long Googling session I stumbled on the solution.

    The URL object you specify must be created as follows:

    URLClassLoader.addURL(new File(pathParam).toURI().toURL());
    

    or in the constructor as follows:

    new URLClassLoader(new URL[]{new File(pathParam).toURI().toURL()},this.getClass().getClassLoader());
    

    Note that the constructor has the parent class-loader as a parameter.

    for the loadClass() method. You need to ensure the path to the class is in binary format (as you are doing already).

    For some reason, even if I create a URL object using the URL(String) constructor it won't work.

    If you go and look at the java.lang.ClassLoader super-class, you will notice that it throws an exception by default. This is why the classloader is important.

    protected Class<?> findClass(String name) throws ClassNotFoundException {
            throw new ClassNotFoundException(name);
        }