web-dev-qa-db-ja.com

Javaクラスのロード元を見つける

Javaクラスローダーが実際にクラスをロードする場所をプログラムで見つける方法を知っている人はいますか?

クラスパスが非常に長くなり、手動検索が実際にはオプションではない大規模なプロジェクトでよく作業します。私は最近 問題 を持っていました。クラスローダーは2つの異なる場所のクラスパス上にあるため、クラスの誤ったバージョンをロードしていました。

それでは、実際のクラスファイルがディスク上のどこにあるのかをクラスローダーに教えてもらうにはどうすればよいでしょうか?

Edit:バージョン不一致のためにクラスローダーが実際にクラスのロードに失敗した場合はどうでしょうか(またはそれ以外の場合)、とにかく読み取る前にどのファイルを読み取ろうとしているかを知ることができますか?

168
luke

次に例を示します。

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
174
Jon Skeet

(ソースを操作せずに)クラスのロード元を見つける別の方法は、オプション-verbose:classを使用してJava VMを開始することです。

93
jiriki
getClass().getProtectionDomain().getCodeSource().getLocation();
71
Dave DiFranco

これは私たちが使用するものです:

public static String getClassResource(Class<?> klass) {
  return klass.getClassLoader().getResource(
     klass.getName().replace('.', '/') + ".class").toString();
}

これは、ClassLoaderの実装に応じて機能します。getClass().getProtectionDomain().getCodeSource().getLocation()

26
Jevgeni Kabanov

オブジェクトのClassLoadernullとして登録されている場合、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";
}
16
OldCurmudgeon

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/

スタイルが悪いかもしれませんが、うまくいきます!

4
ecerer

通常、ハードコーディングは使用しません。最初にclassNameを取得し、次にClassLoaderを使用してクラスURLを取得できます。

        String className = MyClass.class.getName().replace(".", "/")+".class";
        URL classUrl  = MyClass.class.getClassLoader().getResource(className);
        String fullPath = classUrl==null ? null : classUrl.getPath();
1
Hongyang

この同様の質問をご覧ください。 同じクラスを発見するためのツール..

最も重要な障害は、カスタムクラスローダー(dbまたはldapからロードする)がある場合だと思います

1
OscarRyz

このアプローチは、ファイルとjarの両方で機能します。

Class clazz = Class.forName(nameOfClassYouWant);

URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish
0
Adam