i followed the steps described at Create cross platform Java SWT Application . i create a jar which has a swt_browser.jar containing only my class using swt library. then i added other platrom-specific swt jars. i use the below code to load the swt_browser.jar and the platform specific swt library jar. but somehow the call for loading class SWTBrowser complains :
java.lang.ClassNotFoun开发者_JAVA百科dException: org.eclipse.swt.widgets.Layout
can you tell what i am doing wrong?
-----code for loading swt jars-------
ClassLoader parent = Main.class.getClassLoader();
URL.setURLStreamHandlerFactory(new RsrcURLStreamHandlerFactory(parent));
URL swtBrowserFileUrl = new URL("rsrc:swt_browser.jar");
URL swtFileUrl = new URL("rsrc:" + swtFileName);
ClassLoader cl = new URLClassLoader(new URL[]{swtBrowserFileUrl, swtFileUrl}, parent);
Method addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addUrlMethod.setAccessible(true);
addUrlMethod.invoke(cl, swtBrowserFileUrl);
addUrlMethod.invoke(cl, swtFileUrl);
Thread.currentThread().setContextClassLoader(cl);
try {
// Check we can now load the SWT class -this check passes!
Class.forName("org.eclipse.swt.widgets.Layout", true, cl);
} catch (ClassNotFoundException exx) {
System.err.println("Launch failed: Failed to load SWT class from jar: " + swtFileName);
throw new RuntimeException(exx);
}
//this line below throws exception : java.lang.ClassNotFoundException: org.eclipse.swt.widgets.Layout
Class<?> c = Class.forName("com.sun.star.google.gui.SWTBrowser", true, cl);
Object obj = c.newInstance();
Method run = c.getMethod("run", url.getClass()); //$NON-NLS-1$
run.invoke(obj, new Object[]{url});
Your jar has the following file structure:
You are setting up the following ClassLoaders:
- Main classloader
- SWT classloader
The Main classloader has all of the following on its classpath:
- Your app classes
- The jar-in-jar classloader
The SWT classloader is constructed at runtime and has the following on its classpath:
- The SWT classes for your platform
Your loading code asks the SWT classloader to load an SWT class and that works. However, you then ask it to load an application class. It doesn't know about your application class so it delegates to its parent, the Main classloader. This manages to load your application class which then tries to reference an SWT class. This reference is handled by the classloader which loaded your application class - the Main classloader. This doesn't know about the SWT class and throws an exception.
You need to package your application differently. You need to have the following classloaders.
- Main classloader
- SWT classloader
The Main classloader has all of the following on its classpath:
- A single app class which handles building the SWT classloader
- The jar-in-jar classloader
The SWT classloader is constructed at runtime and has the following on its classpath:
- The SWT classes for your platform
- Your app classes
This means that when you load your app class it will be loaded by the SWT classloader. This means that when your app refers to SWT classes the correct classloader is used.
For a working example of this, you can download and examine the following jar: https://github.com/downloads/mchr3k/org.intrace/intrace-ui.jar
EDIT: The ant build file which produced intrace-ui.jar can be seen here: https://github.com/mchr3k/org.intrace/blob/master/org.intrace/build.xml
In particular, the "jar" target handles the packaging.
精彩评论