'-classpath'コマンドライン引数を指定してもjava.class.pathを設定せず、代わりにクラスローダーを作成し、コマンドラインで指定されたクラスパス上のアイテムのすべてのURLをクラスローダーに追加するサードパーティのコードを使用しています、次にそれをコンテキストクラスローダーに設定します。私が書いたこのコードのプラグインクラスで、このクラスローダーのインスタンスを取得し、JavaCompiler.getTask(...の呼び出しで使用できるように、基になるクラスパスを取得するためにそれを使用する必要があります。 )そして他のコードをその場でコンパイルします。ただし、ClassLoaderからClassPathを取得する方法はないようです。また、java.class.pathが設定されていないため、アプリケーションが最初に呼び出された基になるクラスパスにアクセスできないようです...何かアイデアはありますか?
5 に答える
クラスローダーがURLを使用する場合は、である必要がありますURLClassloader
。アクセスできるのは、その親とともにそのクラスパスClassLoader
を定義するURLです。
URLを取得するには、次のようにします。
((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
今日のクラスパスを列挙する最もクリーンな方法は、ClassGraphライブラリを使用することです(私は作成者です)。多くのランタイム環境がもはや使用されていない、および/またはそれらのクラスローダーが拡張されていない、および/またはそれらがいくつかのあいまいなメカニズムを使用しているため、今日コードを移植可能にしたい場合、java.class.path
プロパティの読み取りまたは呼び出しの古い答えはひどく不十分であることに注意してくださいクラスパスを拡張するため(jarのマニフェストファイルのプロパティなど)、および/またはコードをJDK 9+のモジュールとして実行する場合があります(または、コードはJDK9 +の従来のクラスパスで実行されますが、標準のJDKクラスローダーは従来のクラスパスはもう拡張されません)。((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
java.class.path
URLClassLoader
Class-Path:
URLClassLoader
ClassGraphは、膨大な数のクラスパス指定メカニズムとクラスローダーの実装を自動的に処理します。サポートされているほとんどのクラスローダーでは、クラスローダーからクラスパスを取得するためのカスタムリフレクションコードがClassGraph用に記述されています(ClassLoader
APIにはクラスパスを取得するための標準メカニズムがないため、これが必要です)。このために独自のコードを作成することもできますが、おそらくそれはURLClassLoader
多大な労力を費やすことなくサポートされるだけです。したがって、作業はすでに完了しているので、ClassGraphを使用する方がおそらく良いでしょう。
クラスパス(およびモジュールパスに追加された非システムモジュラーjar)を取得するには、次を呼び出します。
List<URI> classpath = new ClassGraph().getClasspathURIs();
Java 9以降では、モジュール(またはjlinkされたjar)がjrt:
URIとともにリストに表示される場合がありますが、これは直接行うことはできません(ClassGraphを使用してリソースとクラスを読み取る以外は、ClassGraphは追加で使用できるため)これらのリソースとクラスにアクセスするためのJPMSAPI)。ClassGraphを使用して、クラスパス内のすべてのクラスやすべてのリソースを列挙またはスキャンすることもできます(ClassGraph wikiを参照)。
Java 9以降のモジュラープロジェクトでModuleReference
は、システムで表示されているモジュールのオブジェクトのリストを取得することもできます。これらは、以下を呼び出すことで取得できます(下位互換性ModuleRef
のあるラッパーでModuleReference
あるため、JDK 7/8でコードをコンパイルできますが、JDK 9+のモジュール機能を利用できます)。
List<ModuleRef> modules =
new ClassGraph()
.enableSystemPackages() // Optional, to return system modules
.getModules();
または、以下を呼び出してオブジェクトのリストを返すことにより、コマンドライン(、--module-path
など)に渡される実際のモジュールパスを取得できます。--patch-module
--add-exports
ModulePathInfo
List<ModulePathInfo> modulePathInfo = new ClassGraph().getModulePathInfo();
後で参照できるように、クラスパスを次の場所に渡す必要がある場合に備えて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");
他の答えがうまくいかない場合は、これを試してください:
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url: urls) {
System.out.println(url.getFile());
}
このコードを空の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>