jarファイルからクラスを読み込むクラスローダー

id:NAT_programming:20060729の続き。jarファイルからクラスを読み込むクラスローダーなら、J2SEAPIにありそうだと思って探してみたら、案の定ありました。java.net.URLClassLoaderクラスです。URLでjarファイルまたはクラスディレクトリを指定するクラスローダー。
一応、使いやすくするためにjarをFileで指定するサブクラスJarClassLoaderを作ってみた。

package nat.champloo.classloader;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * JARファイルからクラスを読み込むクラスローダー
 * @author NAT
 */
public class JarFileClassLoader extends URLClassLoader {
    /**
     * コンストラクタ
     * @param jarFiles クラスを読み込むJARファイルの配列
     * @param parent 親となるクラスローダー
     * @throws MalformedURLException パスを URL として構文解析できない場合
     */
    public JarFileClassLoader(File[] jarFiles, ClassLoader parent) throws MalformedURLException {
        super(toURLs(jarFiles), parent);
    }

    /**
     * コンストラクタ
     * @param jarFile クラスを読み込むJARファイル
     * @param parent 親となるクラスローダー
     * @throws MalformedURLException パスを URL として構文解析できない場合
     */
    public JarFileClassLoader(File jarFile, ClassLoader parent) throws MalformedURLException {
        this(new File[]{jarFile}, parent);
    }

    private static URL[] toURLs(File[] jarFiles) throws MalformedURLException {
        URL[] urls = new URL[jarFiles.length];
        for (int i = 0; i < jarFiles.length; i++) {
            urls[i] = jarFiles[i].toURL();
        }
        return urls;
    }
}

使用例とテストを兼ねたテストケースはこちら。

package nat.champloo.classloader;

import junit.framework.TestCase;;

public class JarClassLoaderTest extends TestCase {
    public void testLoadClass() throws Exception {
        // jarファイル"champloo.jar"からクラスを読み込む
        ClassLoader classLoader = new JarFileClassLoader(
                new File("champloo.jar"), getClass().getClassLoader());
        Object a = classLoader.loadClass("nat.champloo.classloader.A").newInstance();
        assertEquals("nat.champloo.classloader.A", a.getClass().getName());
        assertEquals("A", a.toString());
    }
}

以前の例と同様に、jarファイル"champloo.jar"にはtoString()メソッドが"A"を返すクラスAが入っています。