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


184

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

私は、クラスパスが非常に長くなり、手動検索が実際には選択肢にならないような大規模なプロジェクトによく取り組みます。最近問題がありました、クラスローダーが2つの異なる場所のクラスパスにあるため、クラスローダーが誤ったバージョンのクラスをロードするがありました。

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

編集:バージョンの不一致(または何か他の理由)が原因でクラスローダーが実際にクラスのロードに失敗した場合はどうでしょうか?


4
私は、これはの重複と見なされるべきではないと思う@JarrodRoberson stackoverflow.com/questions/11747833/... この質問は、2008年に頼まれた、その質問は2012年に頼まれたので、
ルーク

回答:


189

次に例を示します。

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

32
冗長な入力を減らすために、短いバージョンを使用することもできます:Test.class.getResource("Test.class")、これはパッケージ名を繰り返さないためです。
メリトン2013

1
クラスが.groovyファイルなどからコンパイルされた場合はどうなりますか?
OndraŽižka2013年

35
@meriton:または、リファクタリングを生き残るために:Test.class.getResource(Test.class.getSimpleName() + ".class")
レオンブロイ2013

1
以下のためにBouncyCastleProvider完全なパッケージ名が必要です。
Pavel Vlasov 2013年

3
getClassLoader()返品可能ですnull。これを処理するためのこのメソッドの拡張については、こちらを参照してください。
OldCurmudgeon 2014年

100

(ソースを操作せずに)クラスがどこから読み込まれるかを確認する別の方法は、オプションでJava VMを起動することです。 -verbose:class


6
これは非常にうまく機能し、null ClassLoaderを持つクラスを処理する問題はありません
lexicalscope

2
@riesプログラムでこれを行う必要がない場合、これは間違いなく進むべき道であり、私の問題は解決しました。ただし、OPはこれをプログラムで行う方法を具体的に尋ねました。
SantiBailors 2017

80
getClass().getProtectionDomain().getCodeSource().getLocation();

4
はい。ただし、セキュリティマネージャーがインストールされていて、必要な権限がない場合は機能しません。
トム・ホーティン-タックライン08/10/23

1
参考までに、NPE = Null Pointer Exception。HTH!
Evgeni Sergeev 2015年

2つの異なる場所から同じクラスをロードできるため、インスタンスへの参照がある限り、このメソッドが推奨されます。
ミゲルPingの

1
また、Java 9+モジュールから呼び出された場合も機能しません(もちろん、2008年には知ることができませんでした)。
Jeff G

28

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

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

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


17

Jonのバージョンは、オブジェクトがBootによってロードされたことを意味するようにClassLoader登録されnullている場合に失敗します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";
}

5

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/

多分悪いスタイルですが、うまくいきます!


3

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

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

URL classUrl = MyClass.class.getClassLoader()。getResource( "/" + className);である必要があります。
アンドリューコーツ

MyClass.classは重要な部分です-getClass()はProxyを返すことができます!次に、MyClass $$ EnhancerBySpringCGLIB $$ a98db882.classのような名前とヌルURLを取得できます。
jalmasi


1

簡単な方法:

System.out.println(java.lang.String.class.getResource(String.class.getSimpleName()+ "。class"));

アウトの例:

jar:file:/ D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class

または

String obj = "簡単なテスト"; System.out.println(obj.getClass()。getResource(obj.getClass()。getSimpleName()+ "。class"));

アウトの例:

jar:file:/ D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class


0

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

Class clazz = Class.forName(nameOfClassYouWant);

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

-1

という名前のクラスで作業していると仮定するとMyClass、次のように動作するはずです。

MyClass.class.getClassLoader();

.classファイルのディスク上の場所を取得できるかどうかは、クラスローダー自体に依存します。たとえば、BCELのようなものを使用している場合、特定のクラスにはディスク上の表現さえありません。


これは、クラスのロードに使用されたClassLoaderを返しますね。.classファイルの場所が見つかりませんか?
Koray Tugay 2014

1
いいえ、ありません。クラスローダーは、実際には完全に異なるクラスパスを参照できます。つまり、実際のクラスの場所を完全に参照することはできません。
トマーシュZato -復活モニカ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.