web-dev-qa-db-ja.com

フォルダーまたはJARから実行時にクラスをロードする方法は?

Javaアプリケーションの構造をスキャンし、いくつかの意味のある情報を提供するJavaツールを作成しようとしています。これを行うには、プロジェクトの場所(JAR/WARまたはフォルダーのみ)からすべての.classファイルをスキャンし、リフレクションを使用してメソッドについて読み取る必要があります。これはほぼ不可能であることが証明されています。

ディレクトリ/アーカイブから特定のクラスをロードできるURLClassloaderに基づいた多くのソリューションを見つけることができますが、クラス名またはパッケージ構造に関する情報がなくてもクラスをロードできるものはありません。

編集:私はこれを不十分に言い表したと思う。私の問題は、すべてのクラスファイルを取得できないということではなく、再帰などでそれを実行し、適切に見つけることができるということです。私の問題は、各クラスファイルのClassオブジェクトを取得することです。

57
Sam Stern

次のコードは、JARファイルからすべてのクラスをロードします。クラスについて何も知る必要はありません。クラスの名前は、JarEntryから抽出されます。

JarFile jarFile = new JarFile(pathToJar);
Enumeration<JarEntry> e = jarFile.entries();

URL[] urls = { new URL("jar:file:" + pathToJar+"!/") };
URLClassLoader cl = URLClassLoader.newInstance(urls);

while (e.hasMoreElements()) {
    JarEntry je = e.nextElement();
    if(je.isDirectory() || !je.getName().endsWith(".class")){
        continue;
    }
    // -6 because of .class
    String className = je.getName().substring(0,je.getName().length()-6);
    className = className.replace('/', '.');
    Class c = cl.loadClass(className);

}

編集:

上記のコメントで示唆されているように、javassistも可能性があります。上記のコードを形成するwhileループの前のどこかでClassPoolを初期化し、クラスローダーでクラスをロードする代わりに、CtClassオブジェクトを作成できます。

ClassPool cp = ClassPool.getDefault();
...
CtClass ctClass = cp.get(className);

CtClassから、すべてのメソッド、フィールド、ネストされたクラスなどを取得できます。javassist apiを見てください: https://jboss-javassist.github.io/javassist/ html/index.html

99
Apfelsaft

Jarファイル内のすべてのクラスをリストします。

public static List getClasseNames(String jarName) {
    ArrayList classes = new ArrayList();

    if (debug)
        System.out.println("Jar " + jarName );
    try {
        JarInputStream jarFile = new JarInputStream(new FileInputStream(
                jarName));
        JarEntry jarEntry;

        while (true) {
            jarEntry = jarFile.getNextJarEntry();
            if (jarEntry == null) {
                break;
            }
            if (jarEntry.getName().endsWith(".class")) {
                if (debug)
                    System.out.println("Found "
                            + jarEntry.getName().replaceAll("/", "\\."));
                classes.add(jarEntry.getName().replaceAll("/", "\\."));
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return classes;
}
9
amicngh

これを行うには、プロジェクトの場所(JAR/WARまたはフォルダーのみ)からすべての.classファイルをスキャンできる必要があります。

フォルダ内のすべてのファイルをスキャンするのは簡単です。 1つのオプションは、フォルダーを示すFileFile.listFiles()を呼び出してから、結果の配列を繰り返すことです。ネストされたフォルダーのツリーをトラバースするには、再帰を使用します。

JARファイルのファイルのスキャンは、JarFile AP​​Iを使用して行うことができます...ネストされた「フォルダー」をトラバースするために再帰する必要はありません。

これらのどちらも特に複雑ではありません。 javadocを読んでコーディングを開始してください。

6
Stephen C