简体   繁体   中英

Java: Automatic Custom ClassLoader

My application uses the Standard Widget Toolkit (SWT) for it's GUI. My problem is that the 32-bit SWT library does not work on a 64-bit JVM. But I don't want to make people select the correct architecture when getting the software. So, I want to bundle both the 32-bit and 64-bit libraries, and auto-detect the architecture during runtime. I found out I can get the correct architecture of the JVM like so:

if (System.getProperty("os.arch").contains("64")) {
    // ...
}

Now all that's left is to load the jar. But the problem is, all the examples I found require that you manually load the class before using it.

Class.forName("MyClass", false, myClassLoader);

So my question is, is it possible to "register" my class loader, so that I don't have to load classes beforehand?


Update: I created my own child class of URLClassLoader and set it as the default class loader with the command line argument -Djava.system.class.loader ; but I get this error:

Error occurred during initialization of VM
java.lang.Error: java.lang.NoSuchMethodException: com.program.LibraryLoader.<init>(java.lang.ClassLoader)
    at java.lang.ClassLoader.initSystemClassLoader(Unknown Source)
    at java.lang.ClassLoader.getSystemClassLoader(Unknown Source)

I think LibraryLoader.<init> refers to the constructor... but it's there ( public LibraryLoader(URI[] urls) ).


Update 2: Almost there, the JVM runs now. I added this constructor to make it work:

public LibraryLoader(ClassLoader classLoader) {
    super(new URL[0], classLoader);
}

But after adding the jars with addPath() ( file:lib/jars/swt.jar ), it only produces a NoClassDefFoundError . Yes, I double-checked that the file exists.

You could try to inject your custom class loader by means of the "java.system.class.loader" property (see ClassLoader#getSystemClassLoader). However, I'd recommend to use OSGi and let the framework do the complicated stuff.

As part of the constructor for your custom ClassLoader, call definePackage with the appropriate information, with the URL pointing to the desired jar file.

This example shows that the custom class loader is called when I try to instantiate a class from swing, because I defined my class loader as the loader of that package.

import java.net.URL;

public class junk extends ClassLoader {

  byte[] dummy = new byte[0];

  public static void main(String[] args) throws Exception {
    new junk();

    new javax.swing.JPanel();

  }

  public junk() throws Exception {
    definePackage("javax.swing","","","","","","",new URL("file://junk.class"));
  }

  public Class<?> findClass(String s) throws java.lang.ClassNotFoundException{
    Class<?> retVal = super.findClass(s);

    System.out.println("delegated responsibility for "+s+" to superclass");

    return retVal;
  }

  public Package getPackage(String s) {
    Package retVal = super.getPackage(s);

    System.out.println("delegated responsibility for "+s+" to superclass");

    return retVal;
  }

}

Result:

delegated responsibility for javax.swing to superclass

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM