JavaでたくさんのJARライブラリを使用して、クラスパスがたくさんあると、クラスが意図していないクラスパスからロードされていてハマることがあります。「ビルドしたはずのクラスなのに、古いクラスが別のJARに格納されていた」なんてトラブルもありました。
WEBアプリケーションなどは、色々なクラスローダーからライブラリが読み込まれたりするので、予想外のライブラリからクラスがロードされるトラブルがあったりします。
もちろん、そんな環境になっているのが一番問題なのですが、気づかずにそうなってしまうこともあります。
そんなときには、あるクラスがどのJARファイル(およびクラスパス)からロードされているかを確認する必要があります。
これはコード上にはあらわれないことで、実行時に決定されるから、なかなか見えにくいものです。
見つける方法
Class#getResource
というメソッドを使えば、URLオブジェクトが得られるため、そこからクラスパスを類推することができます。実行してデバッグ出力してみないと分かりませんが、結構役に立つと思います。
あるクラスXについて調べたいときは、
URL u = X.class.getResource("/" +
X.class.getName().replaceAll("\\.", "/") + ".class");
System.out.println(u);
このようなロジックを実行することで、classファイルのリソースURLを取得します。
文字列置換しているのは、クラスの完全修飾名(foo.bar.Hoge)から、”/foo/bar/Hoge.class”という文字列を作り出しているためです。
JARファイル中に格納されているときは、
jar:file:/c:/foor/bar.jar!/jp/co/hoge/X.class
のように出力されるので、c:/foor/bar.jarの中に存在するXクラスを使用していることが分かります。
JARファイルに入ってないクラスパスフォルダでも見つかります。
file:/c:/myclasses/jp/co/hoge/X.class
propertiesファイルなどの、リソースファイルをどこから取得したかを調べる場合にはこのようにします。
URL u = X.class.getResource("/log4j.properties");
System.out.println(u);
この場合のクラスXは、適当なクラスを使えばよいです。(this.getClass()のようにしてもOK)
「log4j.propertiesを書き換えたつもりが反映されない!いったいどこのlog4jを使っているんだ!?」なんて時に使えば一発です。
(そんな小汚い環境になっているのがそもそも困ったものなんですが)
余談ですが、ビルド時のクラスパスであれば、Eclipseの場合、「ナビゲート」-「型を開く」(Ctrl + Shift + T)でクラス名を入力すれば、どのライブラリから参照するか、すぐに分かります。
ただし、この場合は“ビルド時”に参照しているライブラリであって、“実行時”にどこを参照しているかは別の話です。