更新: この問題は、TestFramework.jar が JUnit に依存しており、(TestFramework) の読み込み時に junit jar が見つからないことが原因である可能性があると思います。私が正しければ、jar がロードされる順序を指定する方法が必要です。
JUnit TestCase の拡張であり、getTestData という名前のメソッドにテスト データを含む Java ソース ファイルをユーザーが指定できるようにするツールを作成しようとしています。次に、このツールは 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);
}
}
コンパイルされたクラス ファイルを実際に検索してロードするコードを次に示します。最初のパラメータは内部を検索するディレクトリです。2 番目のパラメータは、ユーザーが 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);
}
}
}
}
ユーザーが選択したソース ファイルのすべての依存関係が jar であるとは限らず、コンパイルされて "classes" ディレクトリに配置される他のソース ファイルもあることに注意してください。「classes」ディレクトリは、プロジェクト設定を介してランタイム クラスパスに含まれています (GUI の作成を簡素化するために Netbeans を使用しています)。ユーザーが「lib」ディレクトリにjarを動的に追加できるようにしたいので、プロジェクト設定で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 を動的にロードしたいので、これは問題の解決には役立ちません。
- ディレクトリ内のすべての jar をロードしようとする代わりに、junit.jar のみを指定します。これでも、上記と同じ失敗が発生します。
- プロジェクト構成から「クラス」ディレクトリを削除し、同じコードを使用してそれらのクラスを取り込みます。これはコンパイルされたソースを取り込むために機能しますが、jar の問題は修正されません。
- URL で絶対パスではなく相対パスを使用する。これは役に立ちません。
- jar のロードを試行する前後に System.out を追加します。結果は、URLClassLoader の作成中に URL のリストを出力した場合と同じです。最初に作成したときとロードを試行した後では何も変わりません。
私が思いつく唯一のことは、使用しようとしている URLClassLoader が使用されていないということですが、なぜそれが起こるのかわかりません。どんな助けでも大歓迎です。御時間ありがとうございます。