きどたかのブログ

いつか誰かがこのブログからトラブルを解決しますように。

JMockitで拡張クラスローダーに読まれるクラスをモックするのを足掻いた結果

惨敗だ。


クラスローダーの委譲関係は、親が先で通常3つのクラスローダーがいる。


ブートストラップ・クラスローダー
拡張クラスローダー
アプリケーション・クラスローダー(システム・クラスローダー)


MockUp対象クラスが拡張クラスローダーにいる。
クラスを書き換えると、JMockit関連のクラスが埋め込まれるため、いざ動こうとすると拡張クラスローダーからは見付けられない。


じゃあ、拡張クラスローダーにjmockit.jarを読ませればどうなるか。
拡張クラスローダーに読み込ませるには、二つのやり方がある。
  • lib/extにjarを置く
  • -Djava.ext.dirsでディレクトリを指定
後者は、すでに使われているため、指定を増やすときは、前の値も含めて指定することに注意は払う必要がある。
仮に、jmockit.jarを含めたとしても、今度はjunitがないよ、ってなる。
junitを加えると、テストケースが見つからないよ、ってなる。
おいおい、結局全部になるんじゃねーの?


そこから考えられる方針は二つ。
  • 拡張クラスローダーに寄せる
  • アプリケーションクラスローダーに寄せる
やる気が失せるほど、どっちもどっちな予感。
ワクワクしねーから、斜め上を試す。


システムクラスローダーを作ってみる。
システムプロパティ-Djava.system.class.loaderで指定可能。
システムクラスローダーはアプリケーションクラスローダーを親に持ち、新たな委譲関係ができる。
そのため、ClassLoaderを引数に取るpublicコンストラクタが必要となる。
その先、かなりごにょごにょ。
アプリケーションクラスローダーをURLClassLoaderにキャストして、クラスパスをURL配列で掠め取り、委譲関係を辿り拡張クラスローダーを見つけて、リフレクションでそのURLをねじ込む。なんとなく雰囲気でAccessController使ってみたり。


さきほどの拡張クラスローダーに寄せるパターンを実現するための一つの方法として、ねじ込みクラスローダーが完成したわけだが、使う気にならん!


ちなみにjmockitのソースを読む限りでは、Startupを読み込んだクラスローダーがシステムクラスローダーと異なった場合、ちょっとしたことをやっているようだ。
あと、もちろんjavaagentはシステムクラスローダーによって読み込まれることは決まってる。


考えるのをやめよう。幸せは訪れない。