Javaクラスローダーが実際にクラスをロードする場所をプログラムで見つける方法を知っている人はいますか?
クラスパスが非常に長くなり、手動検索が実際にはオプションではない大規模なプロジェクトでよく作業します。私は最近 問題 を持っていました。クラスローダーは2つの異なる場所のクラスパス上にあるため、クラスの誤ったバージョンをロードしていました。
それでは、実際のクラスファイルがディスク上のどこにあるのかをクラスローダーに教えてもらうにはどうすればよいでしょうか?
Edit:バージョン不一致のためにクラスローダーが実際にクラスのロードに失敗した場合はどうでしょうか(またはそれ以外の場合)、とにかく読み取る前にどのファイルを読み取ろうとしているかを知ることができますか?
次に例を示します。
package foo;
public class Test
{
public static void main(String[] args)
{
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("foo/Test.class"));
}
}
これは印刷されました:
file:/C:/Users/Jon/Test/foo/Test.class
(ソースを操作せずに)クラスのロード元を見つける別の方法は、オプション-verbose:class
を使用してJava VMを開始することです。
getClass().getProtectionDomain().getCodeSource().getLocation();
これは私たちが使用するものです:
public static String getClassResource(Class<?> klass) {
return klass.getClassLoader().getResource(
klass.getName().replace('.', '/') + ".class").toString();
}
これは、ClassLoaderの実装に応じて機能します。getClass().getProtectionDomain().getCodeSource().getLocation()
オブジェクトのClassLoader
がnull
として登録されている場合、Jonのバージョンは失敗します。これは、ブートClassLoader
によってロードされたことを暗示しているようです。
この方法はその問題を扱います:
public static String whereFrom(Object o) {
if ( o == null ) {
return null;
}
Class<?> c = o.getClass();
ClassLoader loader = c.getClassLoader();
if ( loader == null ) {
// Try the bootstrap classloader - obtained from the ultimate parent of the System Class Loader.
loader = ClassLoader.getSystemClassLoader();
while ( loader != null && loader.getParent() != null ) {
loader = loader.getParent();
}
}
if (loader != null) {
String name = c.getCanonicalName();
URL resource = loader.getResource(name.replace(".", "/") + ".class");
if ( resource != null ) {
return resource.toString();
}
}
return "Unknown";
}
1行目のみを編集:Main
。class
Class<?> c = Main.class;
String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", "");
System.out.println(path);
出力:
/C:/Users/Test/bin/
スタイルが悪いかもしれませんが、うまくいきます!
通常、ハードコーディングは使用しません。最初にclassNameを取得し、次にClassLoaderを使用してクラスURLを取得できます。
String className = MyClass.class.getName().replace(".", "/")+".class";
URL classUrl = MyClass.class.getClassLoader().getResource(className);
String fullPath = classUrl==null ? null : classUrl.getPath();
この同様の質問をご覧ください。 同じクラスを発見するためのツール..
最も重要な障害は、カスタムクラスローダー(dbまたはldapからロードする)がある場合だと思います
このアプローチは、ファイルとjarの両方で機能します。
Class clazz = Class.forName(nameOfClassYouWant);
URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish