1

実行時にユーザー指定のテキスト トランスレータをロードするコマンド ライン アプリに取り組んでいます (コマンド ライン引数を介して提供されるクラス ファイル/jar へのパス)。基本的に、私はその引数を取得し、それを使用して URLClassLoader を作成しています。次に、Transable インターフェースを実装する URLClassloader で使用できるすべてのクラスを見つける必要があります。

現時点では、このコマンド ライン引数がクラス ファイルを含むディレクトリであることのみを許可しています。ソリューションをかなりシンプルにします (以下のコード)。しかし、正直なところ、jarファイル、jarファイルのディレクトリなどで故障するため、このソリューションは好きではありません...また、loadClassにはパッケージを含む完全な名前が必要であるため、定義されたパッケージを持つクラスでは明らかに故障します。誰でもより良い方法がありますか?

    File d = new File(path);
    if(d.isDirectory()) {
        URL url = d.toURI().toURL();
        ClassLoader cl = new URLClassLoader(new URL[]{url});

        FilenameFilter filter = new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".class");
            }
        };

        for(File f : d.listFiles(filter)) {
            String name = f.getName().substring(0, f.getName().indexOf("."));
            String key = "";
            if(name.endsWith("Translator")) {
                key = name.substring(0, name.indexOf("Translator"));
            }
            else if(name.endsWith("translator")) {
                key = name.substring(0, name.indexOf("translator"));
            }
            else
                key = name;

            Class c = cl.loadClass(name);
            if(Transable.class.isAssignableFrom(c)) {
                Transable t = (Transable)c.newInstance();
                env.registerTranslator(key, t);
            }
            else {
                System.out.println("[ClassLoader] "+c.getCanonicalName()+" will not be loaded. It is not a translator class");
            }
        }
    }
    else {
        throw new Error("NOT IMPLEMENTED");
    }
4

5 に答える 5

4

実装者を明示的に検索する代わりに、Java の Service Provider Interface (SPI) とServiceLoaderクラス (Java 6 で導入) を使用する必要があります。SPI は、Java で記述していることを行うためのほぼ標準的な方法です。

サービスプロバイダーを作成する方法と、ServiceLoader を使用して実行時にサービスプロバイダーを使用する方法については、公式の Java チュートリアルを参照してください。

于 2011-02-17T02:29:04.190 に答える
3

原則として、これは任意のクラスローダーでは機能しません。実際にクラスをロードするために想像できる方法を使用する可能性があり、「ディレクトリリッスン」機能がまったくないためです。

クラスローダはクラス (つまり、クラスのバイトコード) をオンザフライでいつでも生成しloadClass、そのような自動的に定義された各クラスがインターフェイスを実装する TransableClassloader を想像してみてください。プログラムは決して終了しません。


つまり、 にはをURLClassloader使用できgetURLs()、URL にはまたはapi を使用して、試すファイル名 (およびクラス名) のリストを取得できます。URL で指定されたパッケージ階層のルートがあるため、正しいパッケージ名を見つけることも難しくありません。jar:file:JarFileFile

(詳細が必要な場合は、それを言ってください。)


編集:パッケージ名については、階層内のディレクトリ名に対応しています。したがって、 (たとえば)dir/classesに対応するベース URL があり、 という名前のクラスファイルが見つかったdir/classes/com/company/gui/SimpleTranslator.class場合、それは class に対応しcom.company.gui.SimpleTranslatorます。

したがって、ベースプレフィックスを削除し/.(および のカット.class) に置き換えます。(JarFile では、プレフィックスを切り取る必要はありません。)

実際、再帰的な方法を使用してファイル階層をトラバースする場合、単純に文字列を追加するだけで、同じ方法でパッケージ名を作成できます (次の再帰呼び出しのパラメーターとして指定します)。

public void searchClassesInDir(File dir, String packagePrefix) {
    if(dir.isDirectory()) {
        String prefix = packagePrefix + dir.getName() + ".";
        for(File f : dir.listFiles()) {
            searchClasses(f, prefix);
        }
    }
    else {
       String fileName = dir.getName();
       if(! fileName.endsWith(".class"))
           return;
       String className = packagePrefix + fileName.substring(0, fileName.length()-".class".length());
       // now do the rest of your processing
    }
}

searchClasses(new File(url.toURI()), "");
于 2011-02-17T00:27:09.977 に答える
3

これは法案に合うかもしれません。そうでない場合は、それらのソースを調べて、何がうまくいくかを理解できるはずです. http://code.google.com/p/reflections/

于 2011-02-17T00:12:34.757 に答える
0

これは役に立ちますか?

Class c = cl.loadClass(name); から。

クラス メソッド getInterfaces() は、クラスの配列を返します

各クラス名がトランスレータ クラス名と一致するかどうかを確認します。

于 2011-02-17T00:26:48.980 に答える