更新:我认为这个问题可能是由于TestFramework.jar依赖于JUnit,并且以某种方式在加载时(TestFramework)未找到junit jar引起的。仍然不确定解决方案,如果我是对的,我需要一种方法来指定罐装的顺序。在运行时动态添加jar文件时出现NoClassDefFoundError
首先这里是我在做什么的一些背景:我试图创建一个工具,它将允许用户指定一个Java源文件,它是JUnit TestCase的扩展,并在方法中包含测试数据命名为getTestData。然后,该工具将编译java文件,将生成的类文件放在“classes”目录中,加载该类并访问getTestData方法,生成表示测试数据的XML文件。
显然,通过允许用户指定源文件,我还必须确保在编译时,该文件的所有依赖关系都包含在类路径中。所以现在我已经硬编码了一个特定文件的依赖关系,我试图用它来进行测试。用户文件的编译目前正在进行,但加载结果的类会导致一些问题。再次,很明显,加载类我需要确保它所依赖的所有文件都在类路径上,我有。不知何故,在加载类时,它仍然找不到所需的类,并给我一个NoClassDefFoundError。
以下是我用来创建包含“lib”目录中每个jar文件的URL的URLClassLoader的方法。请注意,加载器是一个类变量,因此它可用于我的所有方法,但仅在此一个中进行初始化。
private void loadLibJars()
{
try {
File jarDir = new File("lib");
ArrayList<URL> jarFiles = new ArrayList<URL>();
for(File file: jarDir.listFiles())
{
if(file.isFile() && file.getName().endsWith(".jar"))
{
jarFiles.add(file.toURI().toURL());
}
}
for(URL url:jarFiles)
System.out.println(url);
URL[] urlArray = new URL[jarFiles.size()];
for(int i=0; i<jarFiles.size(); i++)
urlArray[i] = jarFiles.get(i);
loader = new URLClassLoader(urlArray);
}
catch (MalformedURLException ex) {
Logger.getLogger(XmlDataGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
这是实际查找编译后的类文件并加载它的代码。第一个参数是要在其中搜索的目录,第二个参数是用户想要为其生成XML文件的所有已编译类文件的列表。
private void findAndLoadClasses(File classesDir, ArrayList<String>classFileNames)
{
for(File classFile: classesDir.listFiles())
{
if(classFile.isDirectory())
{
System.out.println(classFile+" is a directory, searching inside of it now");
findAndLoadClasses(classFile,classFileNames);
}
else if(classFile.isFile() && classFileNames.contains(classFile.getName()))
{
try
{
String fullClassName = classFile.getPath();
fullClassName = fullClassName.substring(fullClassName.indexOf("\\")+1,fullClassName.lastIndexOf("."));
fullClassName = fullClassName.replaceAll("\\\\", ".");
System.out.println("Full class name: "+fullClassName);
IvrTest testCase = (IvrTest) Class.forName(fullClassName,true,loader).newInstance();
System.out.println("Test data from "+classFile.getName()+": "+testCase.getTestData(...));
}
catch(Exception ex)
{
Logger.getLogger(XmlDataGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
别的东西要注意,可能重要的是,并不是所有的用户选择源文件的依赖关系是罐子,有些是还编制并放置在“类”目录中的其他源文件。 “classes”目录通过项目设置包含在运行时类路径中(我使用Netbeans来简化GUI的创建)。因为我希望用户能够动态地将jar添加到“lib”目录中,所以我没有在项目设置中指定jar。
关于输出和我在这里的问题是我在我的控制台中看到,当我运行代码:
List of class files to search for: [MyTest.class]
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/client.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/delegate.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/model.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/common.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/framework.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/TestFramework.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/junit.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/log4j-1.2.15.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/org.springframework.beans-3.0.1.RELEASE-A.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/org.springframework.context-3.0.1.RELEASE-A.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/org.springframework.core-3.0.1.RELEASE-A.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/org.springframework.web-3.0.1.RELEASE-A.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/org.springframework.web.servlet-3.0.1.RELEASE-A.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/reports.jar
file:/C:/Documents%20and%20Settings/username/My%20Documents/NetBeansProjects/XmlDataGenerator/lib/servlet.jar
classes\my is a directory, searching inside of it now
classes\my\package is a directory, searching inside of it now
classes\my\package\name is a directory, searching inside of it now
Full class name: my.package.name.MyTest
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: junit/framework/TestCase
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:296)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at xmldatagenerator.main.XmlDataGenerator.findAndLoadClasses(XmlDataGenerator.java:299)
at xmldatagenerator.main.XmlDataGenerator.findAndLoadClasses(XmlDataGenerator.java:285)
at xmldatagenerator.main.XmlDataGenerator.findAndLoadClasses(XmlDataGenerator.java:285)
at xmldatagenerator.main.XmlDataGenerator.findAndLoadClasses(XmlDataGenerator.java:285)
at xmldatagenerator.main.XmlDataGenerator.findAndLoadClasses(XmlDataGenerator.java:285)
at xmldatagenerator.main.XmlDataGenerator.findAndLoadClasses(XmlDataGenerator.java:285)
at xmldatagenerator.main.XmlDataGenerator.generateXmlBtnActionPerformed(XmlDataGenerator.java:242)
at xmldatagenerator.main.XmlDataGenerator.access$300(XmlDataGenerator.java:33)
at xmldatagenerator.main.XmlDataGenerator$4.actionPerformed(XmlDataGenerator.java:104)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6267)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
at java.awt.Component.processEvent(Component.java:6032)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
at java.awt.Container.dispatchEventImpl(Container.java:2085)
at java.awt.Window.dispatchEventImpl(Window.java:2478)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Caused by: java.lang.ClassNotFoundException: junit.framework.TestCase
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 73 more
XmlDataGenerator.java线299读取IvrTest testCase = (IvrTest) Class.forName(fullClassName,true,loader).newInstance();
行在这一点上,我不知所措,因为我已经尝试了所有我能想到的方法,例如:
- 将junit.jar添加到运行时类路径(在项目设置中)以确保提供它的错误消失了,它的确如此。这虽然没有帮助解决问题,但因为我想动态加载JAR。
- 仅指定junit.jar,而不是尝试加载目录中的所有jar。这仍然导致与上述相同的失败。
- 从项目配置中删除'classes'目录并使用相同的代码来引入这些类。这有助于引入已编译的源代码,但不能解决jar问题。
- 在URL中使用相对路径而不是绝对路径。这没有帮助。
- 在尝试加载jar之前和之后添加额外的System.out - 结果与在创建URLClassLoader期间打印URL列表时相同,当我第一次创建它时和加载后尝试。
我唯一能想出的就是我尝试使用的URLClassLoader没有被使用,但我不知道为什么会发生这种情况。任何帮助将不胜感激。谢谢你的时间。
为什么不1)帮助解决问题?看起来你正在加载一个扩展TestCase的类,该类在junit.jar中不在你的类路径中。 – maksimov 2012-04-19 15:32:09
它不能解决我的问题,因为我想动态加载罐子。如果我必须在项目设置中指定罐子,那么如果使用它的人需要一个新罐子,我必须重建这个工具。 – Kal 2012-04-19 15:35:26
看看这个:http://stackoverflow.com/questions/402330/is-it-possible-to-add-to-classpath-dynamically-in-java – maksimov 2012-04-19 15:37:36