Reputation: 10091
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.
Upvotes: 1
Views: 5531
Reputation: 667
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
Upvotes: 0
Reputation: 6729
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.
Upvotes: 1