web-dev-qa-db-ja.com

クラスローダーからクラスパスを取得する方法は?

「-classpath」コマンドライン引数を指定するとJava.class.pathを設定せず、代わりにクラスローダーを作成するだけで、コマンドライン上のアイテムのすべてのURLをクラスローダーに指定するサードパーティコードを使用しています、そしてそれをコンテキストクラスローダーに設定します。私が書いたこのコードへのプラグインクラスでは、このクラスローダーのインスタンスを取得し、JavaCompiler.getTask(...の呼び出しで使用できるように、何らかの方法でそれを使用して基になるクラスパスを取得する必要があります)、その場で他のコードをコンパイルします。しかし、とにかくClassLoaderからClassPathを取得する方法はないようで、Java.class.pathが設定されていないため、アプリケーションが最初に呼び出された基になるクラスパスにアクセスできないようです...

47

クラスローダーがURLを使用する場合、URLClassloaderでなければなりません。アクセスできるのは、親ClassLoaderと一緒にclasspathを定義するURLです。

URLを取得するには、次を実行します。

((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
56
Adel Boutros

更新:FastClasspathScannerの開発に3年を費やし、特定のクラスパス環境がこのライブラリで動作していないという多数のバグレポートを提出したため、以下の元の答えはひどく不十分です。 FastClasspathScannerは多数の複雑なクラスパス指定メカニズムを処理するようになりました 。クラスパスを見つけるだけでも、jarとディレクトリをクラスパスに追加する方法は非常に多いため、一般的な場合(スキャンだけでなく)は非常に複雑です。

1つには、以下に示したコードはURLClassLoaderのみを処理し、多くの主要なランタイム環境とコンテナーはこれを拡張せず、独自のクラスローダーをゼロから実装します。ただし、Java 9+の場合、これよりもはるかに複雑になります。従来のクラスパスがまだ存在していても、クラスパスではなくモジュールパスを使用する方向に進むためです。 。モジュールにはURLがありますが、それらは"jrt:/" URL、ない"file:/" URL、およびモジュールURLには、実際にはファイルパスは含まれず、モジュール名のみが含まれます。したがって、一般的にディスク上のモジュールを見つけることさえできません。あなたの唯一のオプションは、(強くカプセル化された)モジュールシステムを使用してモジュールを操作することです。 ここでモジュールパスをスキャンする方法について書きました

FastClasspathScannerは、多数の複雑なクラスパス指定メカニズムを処理するため、車輪を再発明する必要はありません。 FastClasspathScannerからクラスパスエントリのリストを取得する -これにより、さまざまなクラスパス仕様メカニズムを実際に使用して何かを試してみる手間を省くことができます。 (最後のリンクが壊れた場合はおologiesびします-FCSのAPIとドキュメントはまもなく変更されます。)

-

[古い回答-廃止:]

他の答えはほとんどの状況で正しいですが、一部の設定の場合よりも複雑になります。 MavenTomcat およびJUnitには独自のクラスパスサポートがあり、システムクラスパスは使用しません。

これまでのところ、これは私が思いついた最も完全なシステムです(このコードは Fast Classpath Scanner プロジェクトからのものです):

/** The unique elements of the classpath, as an ordered list. */
private final ArrayList<File> classpathElements = new ArrayList<>();

/** The unique elements of the classpath, as a set. */
private final HashSet<String> classpathElementsSet = new HashSet<>();

/** Clear the classpath. */
private void clearClasspath() {
    classpathElements.clear();
    classpathElementsSet.clear();
}

/** Add a classpath element. */
private void addClasspathElement(String pathElement) {
    if (classpathElementsSet.add(pathElement)) {
        final File file = new File(pathElement);
        if (file.exists()) {
            classpathElements.add(file);
        }
    }
}

/** Parse the system classpath. */
private void parseSystemClasspath() {
    // Look for all unique classloaders.
    // Keep them in an order that (hopefully) reflects the order in which class resolution occurs.
    ArrayList<ClassLoader> classLoaders = new ArrayList<>();
    HashSet<ClassLoader> classLoadersSet = new HashSet<>();
    classLoadersSet.add(ClassLoader.getSystemClassLoader());
    classLoaders.add(ClassLoader.getSystemClassLoader());
    if (classLoadersSet.add(Thread.currentThread().getContextClassLoader())) {
        classLoaders.add(Thread.currentThread().getContextClassLoader());
    }
    // Dirty method for looking for any other classloaders on the call stack
    try {
        // Generate stacktrace
        throw new Exception();
    } catch (Exception e) {
        StackTraceElement[] stacktrace = e.getStackTrace();
        for (StackTraceElement elt : stacktrace) {
            try {
                ClassLoader cl = Class.forName(elt.getClassName()).getClassLoader();
                if (classLoadersSet.add(cl)) {
                    classLoaders.add(cl);
                }
            } catch (ClassNotFoundException e1) {
            }
        }
    }

    // Get file paths for URLs of each classloader.
    clearClasspath();
    for (ClassLoader cl : classLoaders) {
        if (cl != null) {
            for (URL url : ((URLClassLoader) cl).getURLs()) {
                if ("file".equals(url.getProtocol())) {
                    addClasspathElement(url.getFile());
                }
            }
        }
    }
}

/** Override the system classpath with a custom classpath to search. */
public FastClasspathScanner overrideClasspath(String classpath) {
    clearClasspath();
    for (String pathElement : classpath.split(File.pathSeparator)) {
        addClasspathElement(pathElement);
    }
    return this;
}

/**
 * Get a list of unique elements on the classpath (directories and files) as File objects, preserving order.
 * Classpath elements that do not exist are not included in the list.
 */
public ArrayList<File> getUniqueClasspathElements() {
    return classpathElements;
}
17
Luke Hutchison

将来の参照のために、クラスパスをProcessBuilderに渡す必要がある場合に備えて:

StringBuffer buffer = new StringBuffer();
for (URL url :
    ((URLClassLoader) (Thread.currentThread()
        .getContextClassLoader())).getURLs()) {
  buffer.append(new File(url.getPath()));
  buffer.append(System.getProperty("path.separator"));
}
String classpath = buffer.toString();
int toIndex = classpath
    .lastIndexOf(System.getProperty("path.separator"));
classpath = classpath.substring(0, toIndex);
ProcessBuilder builder = new ProcessBuilder("Java",
    "-classpath", classpath, "com.a.b.c.TestProgram");
7

他の回答が機能しない場合は、これを試してください:

ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url: urls) {
    System.out.println(url.getFile());
}
5
Yavin5

このコードを空のjspページにドロップして、classLoader階層と各レベルでロードされた関連jarを表示します。

以下のvisit()メソッドも単独で使用できます

<%!
    public void visit(StringBuilder sb, int indent, ClassLoader classLoader) {
        if (indent > 20 || classLoader == null)
            return;
        String indentStr = new String(new char[indent]).replace("\0", "    ");
        sb.append("\n");
        sb.append(indentStr);
        sb.append(classLoader.getClass().getName());
        sb.append(":");
        if (classLoader instanceof Java.net.URLClassLoader) {
            Java.net.URL[] urls = ((Java.net.URLClassLoader)classLoader).getURLs();
            for (Java.net.URL url : urls) {
                sb.append("\n");
                sb.append(indentStr);
                sb.append(url);
            }
        }
        sb.append("\n");
        visit(sb, indent + 1, classLoader.getParent());
    }

%>

<%
StringBuilder sb = new StringBuilder();
visit(sb,1,this.getClass().getClassLoader());
%>
<pre>
<%=sb%>
</pre>
0
Prashant Bhate