简体   繁体   English

奇怪的类路径.NoClassDefFoundError错误

[英]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. 这很奇怪,也不是最好的解决方案,但是我只是继续将MY JAVA CODE(com。*)这些类放在swt.jar中,以便swt.jar和我的类在相同的时刻和相同的时间加载。类加载器。 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 编辑:我在这里添加了大多数代码: 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. 这是奇怪的找不到classdef的错误。 Here is the scenario which is a little different by 90% of my code works. 这是90%的代码正常工作的情况。 Please ignore that I am using Clojure, I have also done this with regular java code and still get the same error. 请忽略我正在使用Clojure,我也使用常规的Java代码完成了此操作,但仍然收到相同的错误。

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. 我最初的想法是,我可以创建类加载器,将jar的文件路径/ URL添加到类加载器,然后启动代码。 But apparently there is some strangeness going on. 但是显然有一些奇怪的事情正在发生。

  1. I have ONE jar file that dynamically loads 4-5 auxillary jar files. 我有一个jar文件,可以动态加载4-5个辅助jar文件。 It is built on a simple URLClassLoader. 它基于简单的URLClassLoader构建。 I want to do this because I can have a user click on one jar file and launch the application. 我想要这样做是因为我可以让用户单击一个jar文件并启动该应用程序。 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. 通过单击此jar文件,应用程序将从文件系统加载jar文件。 Eg the application loads swt.jar (Eclipse's widget toolkit) and some other jars. 例如,应用程序加载了swt.jar(Eclipse的小部件工具包)和其他一些jar。

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. 3(但不用担心),我的应用程序是基于Clojure(动态编程语言)构建的,第一个启动的应用程序是此Clojure脚本。 Most of my application is within the clojure script. 我的大部分应用程序都在clojure脚本中。

4. Everything up to 1-3 works fine. 4. 1-3以下的所有东西都可以正常工作。 The application loads and clojure script runs, the SWT GUI application runs, etc. 应用程序加载并运行clojure脚本,SWT GUI应用程序运行,等等。

  1. Here is the part that doesn't work. 这是无效的部分。

  2. I have an existing java library, call it my-swt-gui.jar. 我有一个现有的Java库,将其称为my-swt-gui.jar。 That is also a swt application. 这也是一个swt应用程序。 It is basically another gui application is already built. 基本上,这是另一个已构建的gui应用程序。 I am trying to load the window from my current clojure/swt application. 我正在尝试从当前的clojure / swt应用程序加载窗口。 For some reason, the JAVA oriented library won't recognize SWT and I get noclassdef errors. 由于某些原因,面向JAVA的库无法识别SWT,并且出现noclassdef错误。

Here is the strangeness. 这是奇怪的地方。 And I will identify where I think there might be oddities. 我会确定我认为可能存在奇怪之处。

Entitis: A. The java oriented classloader. 实体:A.面向Java的类加载器。 In the java classloader, I launch the clojure application. 在Java类加载器中,我启动clojure应用程序。 SWT and other jar files are loaded with this classloader. SWT和其他jar文件都通过该类加载器加载。 B. The Clojure oriented code that gets invoked by section entity a. B.由节实体a调用的面向Clojure的代码。 The clojure code is a swt based GUI application. clojure代码是基于swt的GUI应用程序。 B works fine. B工作正常。 C. Java code that contains another GUI window. C.包含另一个GUI窗口的Java代码。 For some reason, this library wont load and I am getting the error, noclassdef. 由于某种原因,该库无法加载,并且出现错误noclassdef。

NOTE: I KNOW FOR A FACT THAT the SWT class is actually in the classpath or I would get a NoClassFound exception. 注意:我实际上知道SWT类实际上在类路径中,否则我会收到NoClassFound异常。 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? 注意:SWT包含win32 dll可能也是一个问题吗? Maybe accessing the win32 dll jar the first time works but with the java code it doesn't work? 也许第一次访问win32 dll jar可以,但是使用Java代码却不起作用? But that is strange. 但这很奇怪。 Why would SWT work and then not work? 为什么SWT工作然后又不工作?

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. 这就是我尝试加载java swt窗口的方式。 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 { 公共静态最终void createPDFWindowShell(IStartService服务,最终Object Shell,最终Object globalClassLoader)引发异常{

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 “全局”类加载器委托给类加载器A来加载SWT类
  2. "Global" classloader delegates to classloader B to load Clojure code “全局”类加载器委托给类加载器B来加载Clojure代码
  3. Clojure code tries to dynamically load SWT classes via the only classloader it knows about -- that is, classloader B Clojure代码尝试通过它知道的唯一的类加载器(即,类加载器B)动态加载SWT类。
  4. Classloader B doesn't know where to find them, and blows up Classloader B不知道在哪里找到它们,然后炸毁

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 . 这不是一个专门的解决方案,但是听起来您正在复制One-Jar中已经存在的许多功能。

You can bundle your code, along with all of your auxiliary jars, into a single jar file. 您可以将代码以及所有辅助jar捆绑到一个jar文件中。 The One-Jar classloader will work it out at runtime. One-Jar类加载器将在运行时进行处理。 It has saved me from having to write custom classloader code several times. 它使我不必多次编写自定义类加载器代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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