NoClassDef Issue, possibly my fault with the classloaders

15 views
Skip to first unread message

BerlinBrown

unread,
Jun 30, 2009, 6:11:58 PM6/30/09
to Clojure
Pre Notes: I put most of the code for my unit testing here:

http://groups.google.com/group/clojure/web/MostCodeIssue.java
http://groups.google.com/group/clojure/web/NoClassDefIssue.zip
http://clojure.googlegroups.com/web/MostCodeIssue.java?gsc=XGm71wsAAAA6-FUP8n2vUln2lQc9yyLJ

--------

This is the strange no classdef not found error. Here is the scenario
which is a little different by 90% of my code works. Please ignore
that I am using Clojure, I have also done this with regular java code
and still get the same error.

Ideally, I was hoping for some help on custom classloader. My initial
thought was that I could create the classloader, add the filepath/url
of the jars to the classloader and I could launch my code. But
apparently there is some strangeness going on.

1. I have ONE jar file that dynamically loads 4-5 auxillary jar
files. It is built on a simple URLClassLoader. I want to do this
because I can have a user click on one jar file and launch the
application. So there is one item that the user has to worry about.
2. By clicking on this jar file, the application loads jar files
from the filesystem. E.g. the application loads swt.jar (Eclipse's
widget toolkit) and some other jars.

3 (but don't worry about it), my application is built on Clojure (the
dynamic programming language), the first application to launch is this
Clojure script. Most of my application is within the clojure script.
4. Everything up to 1-3 works fine. The application loads and clojure
script runs, the SWT GUI application runs, etc.

1. Here is the part that doesn't work.
2. I have an existing java library, call it my-swt-gui.jar. That is
also a swt application. It is basically another gui application is
already built. I am trying to load the window from my current clojure/
swt application. For some reason, the JAVA oriented library won't
recognize SWT and I get noclassdef errors.

Here is the strangeness. And I will identify where I think there might
be oddities.

Entitis: A. The java oriented classloader. In the java classloader, I
launch the clojure application. SWT and other jar files are loaded
with this classloader. B. The Clojure oriented code that gets invoked
by section entity a. The clojure code is a swt based GUI application.
B works fine. C. Java code that contains another GUI window. For some
reason, this library wont load and I am getting the error, noclassdef.

NOTE: I KNOW FOR A FACT THAT the SWT class is actually in the
classpath or I would get a NoClassFound exception. I am not getting
that exception. Something else is going on.

Note: could it also be an issue with the fact that SWT includes win32
dlls? Maybe accessing the win32 dll jar the first time works but with
the java code it doesn't work? But that is strange. Why would SWT work
and then not work?
I can't show you all the code, I hope I can show you the relevant
pieces.

Here is the main classloader code:

public static final String [] JAVA_LIBRARIES = {
"lib\\log4j-1.2.15.jar",
"lib\\octane_commons.jar",
"lib\\clojure.jar",
"lib\\swt\\win32\\swt.jar",
"lib\\jfreechart\\jcommon-1.0.15.jar",
"lib\\jfreechart\\jfreechart-1.0.12.jar",
"lib\\jfreechart\\jfreechart-1.0.12-swt.jar",
"lib\\pdf\\minium.jar",
"lib\\pdf\\tagsoup-1.2.jar",
"lib\\pdf\\core-renderer.jar",
"lib",
"conf",
"src"
};

My classloader code is based on jetty's classloader and it works OK
but I keep get ting classnotdef errors. Strange ones. I can see a
clear distinction between classnotfound errors. If the file path to
the jar is invalid then I get classnotfound, easy to detect and fix.

Here is essentially the classloader code for future reference.

Classpath classpath = new Classpath();

boolean res = classpath.addComponent(libFilePath);

/// Classloader

private class Loader extends URLClassLoader {
String name;
Loader(URL[] urls, ClassLoader parent) {
super(urls, parent);
name = "StartLoader" + Arrays.asList(urls);
}

public String toString() {
return name;
}
}

//// Then set the classloader
//// where the URLs are the JAR libraries:
URL [] urls = new URL[NUMBER_OF_JARS];
for (x in urls) {
urls[i] = new URL("THE JAR PATH");
}

ClassLoader parent = Thread.currentThread().getContextClassLoader
();
if (parent == null) {
parent = Classpath.class.getClassLoader();
}
if (parent == null) {

parent = ClassLoader.getSystemClassLoader();
}
return new Loader(urls, parent);

/////////////

And this is how I tried to load the java swt window. I tried to print
out as much about the classloader and change to different classloader.

public static final void createPDFWindowShell(IStartService service,
final Object shell, final Object globalClassLoader) throws Exception {

if ((service != null) && (shell != null)) {
synchronized(service) {
service.runService();
Thread.sleep(80);
}
} else {
System.err.println("Invalid arguments : service => " + service + "
shell =>" + shell);
return;
} // End of the if //

final ClassLoader cl = globalClassLoader == null ? service.getClass
().getClassLoader() : (ClassLoader) globalClassLoader;
System.out.println("Service Class Loader.1: " + service.getClass
().getClassLoader());
System.out.println("Service Class Loader.2 : " + cl);
System.out.println("-----------------");
System.out.println("[From DynaClass.1] : " + cl.loadClass
("com.octane.start.services.IStartService"));
System.out.println("[From DynaClass.2] : " + cl.loadClass
("org.eclipse.swt.SWT"));
System.out.println("[From DynaClass.3] : " + cl.loadClass
("org.eclipse.swt.events.SelectionListener"));
System.out.println("-----------------");

final Class listenerTargetClass = cl.loadClass
("org.eclipse.swt.events.SelectionListener");
final ClassLoader newCl = globalClassLoader == null ? service.getClass
().getClassLoader() : (ClassLoader) globalClassLoader;

// Now launch the shell //
//final Class winClass = Class.forName
("com.ca.util.gui.SimplePFSXHtmlPDFWin");
final Class winClass = cl.loadClass
("com.ca.util.gui.SimplePFSXHtmlPDFWin");
final Method methodCreate = winClass.getMethod("createPDFWindowShell",
new Class [] { Object.class });
methodCreate.invoke(null, shell);

}

Here is the error:

[java] [INFO : Classpath Loader Check] : valid files=17 / total=17
[java] [Classpath Loader] - thread class loader parent == false
[java] [INFO : Classpath Loader Check] : classpath=StartLoader[file:/C
%3a/Program%20Files/Java/jdk1.5.0_11/lib/tools.jar, file:/C%3a/usr/
local/pfs/projects/octane/lib/log4j-1.2.15.jar, file:/C%3a/usr/local/
pfs/projects/octane/lib/octane_commons.jar, file:/C%3a/usr/local/pfs/
projects/octane/lib/clojure.jar, file:/C%3a/usr/local/pfs/projects/
octane/lib/swt/win32/swt.jar, file:/C%3a/usr/local/pfs/projects/octane/
lib/jfreechart/jcommon-1.0.15.jar, file:/C%3a/usr/local/pfs/projects/
octane/lib/jfreechart/jfreechart-1.0.12.jar, file:/C%3a/usr/local/pfs/
projects/octane/lib/jfreechart/jfreechart-1.0.12-swt.jar, file:/C%3a/
usr/local/pfs/projects/octane/lib/jfreechart/gnujaxp.jar, file:/C%3a/
usr/local/pfs/projects/octane/lib/jfreechart/swtgraphics2d.jar, file:/C
%3a/usr/local/pfs/projects/octane/lib/jfreechart/jfreechart-1.0.12-
experimental.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/
xercesImpl.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/
minium.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/
tagsoup-1.2.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/core-
renderer.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/, file:/C
%3a/usr/local/pfs/projects/octane/conf/, file:/C%3a/usr/local/pfs/
projects/octane/src/]
[java] Active threads : 3
[java] class clojure.lang.Script
[java] class org.eclipse.swt.SWT
[java] interface org.eclipse.swt.events.SelectionListener
[java] class org.apache.log4j.Logger
[java] class org.xhtmlrenderer.util.XRLog
[java] [INFO] Thread ID : Thread[Thread-3,5,main]
[java] Service Class Loader.1: sun.misc.Launcher
$AppClassLoader@92e78c
[java] Service Class Loader.2 : StartLoader[file:/C%3a/Program
%20Files/Java/jdk1.5.0_11/lib/tools.jar, file:/C%3a/usr/local/pfs/
projects/octane/lib/log4j-1.2.15.jar, file:/C%3a/usr/local/pfs/
projects/octane/lib/octane_commons.jar, file:/C%3a/usr/local/pfs/
projects/octane/lib/clojure.jar, file:/C%3a/usr/local/pfs/projects/
octane/lib/swt/win32/swt.jar, file:/C%3a/usr/local/pfs/projects/octane/
lib/jfreechart/jcommon-1.0.15.jar, file:/C%3a/usr/local/pfs/projects/
octane/lib/jfreechart/jfreechart-1.0.12.jar, file:/C%3a/usr/local/pfs/
projects/octane/lib/jfreechart/jfreechart-1.0.12-swt.jar, file:/C%3a/
usr/local/pfs/projects/octane/lib/jfreechart/gnujaxp.jar, file:/C%3a/
usr/local/pfs/projects/octane/lib/jfreechart/swtgraphics2d.jar, file:/C
%3a/usr/local/pfs/projects/octane/lib/jfreechart/jfreechart-1.0.12-
experimental.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/
xercesImpl.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/
minium.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/
tagsoup-1.2.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/pdf/core-
renderer.jar, file:/C%3a/usr/local/pfs/projects/octane/lib/, file:/C
%3a/usr/local/pfs/projects/octane/conf/, file:/C%3a/usr/local/pfs/
projects/octane/src/]
[java] -----------------
[java] [From DynaClass.1] : interface
com.octane.start.services.IStartService
[java] [From DynaClass.2] : class org.eclipse.swt.SWT
[java] [From DynaClass.3] : interface
org.eclipse.swt.events.SelectionListener
[java] -----------------
[java] java.lang.reflect.InvocationTargetException
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke
(NativeMethodAccessorImpl.java:39)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at com.octane.start.OctaneClojureScript.invokeVarInvoke
(OctaneClojureScript.java:89)
[java] at com.octane.start.OctaneClojureScript.invokeContract
(OctaneClojureScript.java:118)
[java] at com.octane.start.OctaneClojureScript.main
(OctaneClojureScript.java:129)
[java] at
com.octane.start.services.ClassPathLoaderService.runService
(ClassPathLoaderService.java:225)
[java] at com.octane.start.OctaneLauncherMain.runClasspathService
(OctaneLauncherMain.java:73)
[java] at com.octane.start.OctaneLauncherMain.main
(OctaneLauncherMain.java:97)
[java] Caused by: java.lang.NoClassDefFoundError: org/eclipse/swt/
events/SelectionListener (octane_main_window.clj:0)
[java] at clojure.lang.Compiler.eval(Compiler.java:4543)
[java] at clojure.lang.Compiler.load(Compiler.java:4857)
[java] at clojure.lang.RT.loadResourceScript(RT.java:326)
[java] at clojure.lang.RT.loadResourceScript(RT.java:317)
-------------

Daniel

unread,
Jul 15, 2009, 12:54:43 AM7/15/09
to clo...@googlegroups.com
Resurrection
Is this still a problem? If yes, I recommend to look into using an
OSGi framework for your classloading. Classloaders are non-trivial and
it's very easy to trip, to introduce subtle bugs, or fragile things
that break later. Using an established technology for dealing with the
problem is IMHO preferred. And mind you that you don't have to do all
that much to make it work. OSGi is based on Manifest.MF metadata, but
you can use PAX Construct use existing jars that don't have proper
metadata as dependencies in OSGi. In that way you can have the
benefits of OSGi without too much effort to get you started (you can
create the proper versions later). Have a look at all the PAX
Utilities [1], as they can make your life so much easier.

[1] http://wiki.ops4j.org/display/ops4j/Pax

Cheers,
Daniel
Reply all
Reply to author
Forward
0 new messages