UPDATE: I think the problem might be because TestFramework.jar is dependent on JUnit and somehow does not find the junit jar when it loads (TestFramework). Still not sure about the solution, if I'm right, I need to specify the order in which banks are loaded.
First, Iโll talk about what Iโm doing: Iโm trying to create a tool that allows users to specify the java source file, which is a JUnit TestCase extension, and contains test data in the getTestData method. Then this tool will compile the java file, put the resulting class file in a directory "classes" will load the class and gain access to the getTestData method, create XML files representing the test data.
Obviously, allowing the user to specify the source file, I also need to make sure that all the dependencies for this file are included in the class path at compilation. Therefore, at the moment I have hardcoded the dependencies for one specific file, which I am trying to use for testing purposes. Compiling a user file currently works, but loading the resulting class causes some problems. Again, it is obvious that in order to load the class I need to make sure that all the files on which it depends are on the path to the classes that I have. Somehow, while loading a class, it still cannot find the required classes and gives me a NoClassDefFoundError.
The following is the method I use to create a URLClassLoader containing the URL for each of the jar files in the "lib" directory. Please note that the loader is a class variable, therefore it is available for all my methods, but it is initialized only in this.
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); } }
Here is the code that actually finds the compiled class file and loads it. The first parameter is the directory to search inside, the second parameter is a list of all compiled class files that the user wants to generate XML files for.
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); } } } }
Something else to note, which may be important, is that not all dependencies for the user selected source file are jars, some of them are other source files that are also compiled and placed in the classes directory. The "classes" directory is included in the runtime class pool through project settings (I use Netbeans to simplify GUI creation). Since I want the user to be able to dynamically add banks to the "lib" directory, I do not specify banks in the project settings.
As for the output and the problems I came across, this is what I see in the console when I run the code:
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 line 299 is a line that reads IvrTest testCase = (IvrTest) Class.forName(fullClassName,true,loader).newInstance();
At this moment, I am at a loss because I have tried everything I can think of, for example:
- Adding junit.jar to the path of the execution path (in the project settings) to make sure that this error goes away and what it does. This does not help to fix the problem, although I want to dynamically load banks.
- Specifying only junit.jar instead of loading all banks in a directory. This still leads to failure, as indicated above.
- Removing the "classes" directory from the project configuration and using the same code to enter these classes. This works to cite compiled sources, but does not fix the problem with banks.
- Using relative paths in URLs instead of absolute. It does not help.
- Adding an additional System.out before and after trying to load cans - the results are the same as when listing a list of URLs when creating URLClassLoader, nothing changed between when I first created it and after loading it tried.
The only thing I can think of is that some kind of URLClassLoader that I'm trying to use is not used, but I have no idea why this will happen. Any help would be greatly appreciated. Thank you for your time.