简体   繁体   中英

Strange Classpath, .NoClassDefFoundError errors

Edited: SOLUTION FOUND. This is strange and not the best solution, but I just went ahead and put MY JAVA CODE (com.*) the classes in the swt.jar so that swt.jar and my classes are loaded at the exact same moment and by the same classloader. Not the best solution but a temporary fix

Edited: I added most of the code here: http://groups.google.com/group/clojure/browse_thread/thread/1d7dd4913b2f9aa7 http://groups.google.com/group/clojure/web/NoClassDefIssue.zip http://groups.google.com/group/clojure/web/MostCodeIssue.java

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. Eg 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)
 [java]     at clojure.lang.RT.load(RT.java:395)
 [java]     at clojure.lang.RT.load(RT.java:367)
 [java]     at clojure.core$load__5058$fn__5061.invoke(core.clj:3734)
 [java]     at clojure.core$load__5058.doInvoke(core.clj:3733)
 [java]     at clojure.lang.RestFn.invoke(RestFn.java:413)
 [java]     at clojure.core$load_one__5010.invoke(core.clj:3578)
 [java]     at clojure.core$load_lib__5031.doInvoke(core.clj:3615)
 [java]     at clojure.lang.RestFn.applyTo(RestFn.java:147)
 [java]     at clojure.core$apply__3243.doInvoke(core.clj:390)
 [java]     at clojure.lang.RestFn.invoke(RestFn.java:443)
 [java]     at clojure.core$load_libs__5043.doInvoke(core.clj:3641)
 [java]     at clojure.lang.RestFn.applyTo(RestFn.java:142)
 [java]     at clojure.core$apply__3243.doInvoke(core.clj:390)
 [java]     at clojure.lang.RestFn.invoke(RestFn.java:443)
 [java]     at clojure.core$require__5049.doInvoke(core.clj:3701)
 [java]     at clojure.lang.RestFn.invoke(RestFn.java:413)
 [java]     at clojure.lang.Var.invoke(Var.java:346)
 [java]     ... 10 more
 [java] Caused by: java.lang.NoClassDefFoundError: org/eclipse/swt/events/SelectionListener
 [java]     at java.lang.Class.getDeclaredMethods0(Native Method)
 [java]     at java.lang.Class.privateGetDeclaredMethods(Class.java:2395)
 [java]     at java.lang.Class.getMethod0(Class.java:2642)
 [java]     at java.lang.Class.getMethod(Class.java:1579)
 [java]     at com.octane.start.PDFDynamicStartWin.createPDFWindowShell(PDFDynamicStartWin.java:39)
 [java]     at octane.toolkit.octane_core_widgets$pdf_handler__2659.invoke(octane_core_widgets.clj:81)
 [java]     at octane.toolkit.octane_core_widgets$fn__2662$fn__2664.invoke(octane_core_widgets.clj:87)
 [java]     at clojure.proxy.org.eclipse.swt.events.SelectionAdapter.widgetSelected(Unknown Source)
 [java]     at org.eclipse.swt.widgets.TypedListener.handleEvent(Unknown Source)
 [java]     at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source)
 [java]     at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source)
 [java]     at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source)
 [java]     at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
 [java]     at octane.toolkit.octane_main_window$create_gui_window__2990.invoke(octane_main_window.clj:234)
 [java]     at octane.toolkit.octane_main_window$main_1__2994.invoke(octane_main_window.clj:246)
 [java] Processing Time : 6235
 [java]     at octane.toolkit.octane_main_window$_main__2998.doInvoke(octane_main_window.clj:250)
 [java]     at clojure.lang.RestFn.invoke(RestFn.java:402)
 [java]     at octane.toolkit.octane_main_window$eval__3001.invoke(octane_main_window.clj:259)
 [java]     at clojure.lang.Compiler.eval(Compiler.java:4532)
 [java]     ... 30 more

-

I've seen similar problems in a simpler scenario where a class loaded by a child classloader tries to get a class loaded by a parent classloader to dynamically load one of the child classloader's siblings -- it doesn't work, because the child -> parent relationship is only one-way.

Without all the code I can't be sure, but I suspect something like the following is happening:

  1. "Global" classloader delegates to classloader A to load SWT classes
  2. "Global" classloader delegates to classloader B to load Clojure code
  3. Clojure code tries to dynamically load SWT classes via the only classloader it knows about -- that is, classloader B
  4. Classloader B doesn't know where to find them, and blows up

Does that help?

Not a solution specifically, but it sounds like you are duplicating a lot of functionality that is already present in One-Jar .

You can bundle your code, along with all of your auxiliary jars, into a single jar file. The One-Jar classloader will work it out at runtime. It has saved me from having to write custom classloader code several times.

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