Search code examples
javaclassloadernoclassdeffounderrorurlclassloader

Custom URLClassLoader, NoClassDefFoundError when run


I've created my own URLClassLoader, and set it as the system classloader via java.system.class.loader. It's initialized and everything, but the classes I'm trying to load aren't found. Here's the URLClassLoader:

public class LibraryLoader extends URLClassLoader
{
    public LibraryLoader(ClassLoader classLoader)
    {
        super(new URL[0], classLoader);
    }
    synchronized public void addJarToClasspath(String jarName) throws MalformedURLException, ClassNotFoundException
    {
        File filePath = new File(jarName);
        URI uriPath = filePath.toURI();
        URL urlPath = uriPath.toURL();

        System.out.println(filePath.exists());
        System.out.println(urlPath.getFile());

        addURL(urlPath);
    }
}

I've confirmed that the jar exists, and that the path is correct. This is how I call it in my program:

LibraryLoader loader = (LibraryLoader) ClassLoader.getSystemClassLoader();
loader.addJarToClasspath("swt.jar");

This is the exception that I get (line 166 refers to the line at which I try to create a new Point:

Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/swt/graphics/Point
        at mp.MyProgram.loadArchitectureLibraries(MyProgram.java:116)
        at mp.MyProgram.main(MyProgram.java:90)
Caused by: java.lang.ClassNotFoundException: org.eclipse.swt.graphics.Point
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 2 more

I even tried explicitly loading the class like so:

Class.forName("org.eclipse.swt.graphics.Point", false, loader);

What might be causing this? Shouldn't it "just work"?


Update: Here's the important code from MyProgram

public class MyProgram
{
    // ...

    public static void main(String[] args)
    {
        loadArchitectureLibraries();

        // ...
    }

    public static void loadArchitectureLibraries()
    {
        LibraryLoader loader = (LibraryLoader) ClassLoader.getSystemClassLoader();

        String architecture = System.getProperty("os.arch");
        try {
            if (architecture.contains("64")) {
                loader.addJarToClasspath("swt-3.6.1-win32-win32-x86_64.jar");
            } else {
                loader.addJarToClasspath("swt-3.6.1-win32-win32-x86.jar");
            }

            Class.forName("org.eclipse.swt.graphics.Point", false, loader);
            org.eclipse.swt.graphics.Point pt = new org.eclipse.swt.graphics.Point(0, 0);

        } catch (Exception exception) {

            exception.printStackTrace();
            System.out.println("Could not load SWT library");
            System.exit(1);
        }
    }
}

Update 2: Here's an SSCCE: http://nucleussystems.com/files/myprogram.zip . Call java -Djava.system.class.loader=mp.LibraryLoader -jar myprogram.jar.


Solution

  • It's visible from a (few) mile(s) away you are not using the custom classloader beside Class.forName

    The ClassNoDefFoundError occurs since the classloader that has loaded current class MyProgram attempts to load org.eclipse.swt.graphics.Point.

    You need to load another class (call it launcher) via Class.forName and then start from there - implement some interface (even runnable will do) and call it.


    edit

    How to do it, a simplistic scenario.
    1. Create another class called mp.loader.Launcher that implements Runnable like that.

    public class Launcher implements Runnable{
    public void run(){
      org.eclipse.swt.graphics.Point pt = new org.eclipse.swt.graphics.Point(0, 0);
      //whatever, start from here.
    }
    }
    

    2. Place it in another jar called swt-loader.jar.

    in MyProgram class use:

    loader.addJarToClasspath("swt-loader.jar");
    Runnable r = (Runnable) Class.forName("mp.loader.Launcher", true, loader);
    r.run();//there you have