JarClassLoader

Jarファイル用のクラスローダを作りました。
例のDBを縦に表示するヤツの中で使っています。
あれはJDBCのパスを実行時に設定できます。
つまり、クラスパスを設定していないところからクラスを読み込んでます。

通常はこんな感じで接続しますよね。

Class.forName(driverName);
Connection conn = Connection.getConnection(url, user, password);

独自クラスローダを使う場合は以下のようになります。

String[] jarnames = ... // 複数のJarファイルが設定可能
JarClassLoader jarClassLoader = new JarClassLoader();
jarClassLoader.setJarFilenames(jarnames);
Class driverClass = Class.forName(driverName, true, jarClassLoader);
Driver driver = (Driver) driverClass.newInstance();
DriverManager.registerDriver(driver);
Properties prop = new Properties();
prop.put("user", user);
prop.put("password", pass);
Connection conn = driver.connect(url, prop);

以下がソースです。よければどうぞ。

import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarClassLoader extends ClassLoader {

    ArrayList jarnames;
    /**
     * @param paths 個々のパスには末尾にセパレータをつけないこと。
     */
    public JarClassLoader() {
        this.jarnames = new ArrayList();
    }
    public void setJarFilenames(ArrayList jarnames) {
        this.jarnames = jarnames;
    }
    
    public Class findClass(String name) {
        byte b = loadClassData(name);
        if (b == null) return null;
        return defineClass(name, b, 0, b.length);
    }

    
    /**
     * 指定されたパスを使って、サーバのクラスを取得する.
     */
    private byte loadClassData(String name) {
        for (int i=0; i<jarnames.size(); i++) {
            String jarname = (String) jarnames.get(i);
            byte bytes = loadClassData1(name, jarname);
            if (bytes != null) return bytes;
        }
        return null;    // 見つからなかった(;_;)
    }
    private byte loadClassData1(String name, String jarname) {
        String fname = name.replace('.', '\\') + ".class";
        String fname2 = name.replace('.', '/') + ".class";
        try {
            JarFile jarfile = new JarFile(jarname);
            JarEntry entry = jarfile.getJarEntry(fname);
            if (entry == null) {
                entry = jarfile.getJarEntry(fname2);
            }
            if (entry == null) return null;     // 見つからなかった(;_;)
            BufferedInputStream in = new BufferedInputStream(jarfile.getInputStream(entry));
            byte[] bytes = new byte[(int) entry.getSize()];
            int size = in.read(bytes);
            assert size == entry.getSize();
            in.close();
            return bytes;
        } catch (IOException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        }
        return null;    // 見つからなかった(;_;)
    }
}