クラスパス内の特定のリソースを照会するために Google Reflections ライブラリを使用しています。これらのリソースは、プロジェクトのクラスと同じ場所にあります。
Eclipse で単体テストとして実行すると成功する単体テストをいくつか作成しましたが、Maven で (maven install
たとえば a を使用して) 実行しようとすると、期待どおりに動作しません。いくつかのデバッグの後、明らかに問題は、Maven で実行すると、リフレクション ライブラリがリソースが配置されているクラスパス URL を見つけられないことです。
Reflections が検査する必要があるクラスパス URL をどのように決定するかを調査して、その結論に達しました。例として、次のメソッドは、Reflections が指定されたクラス ローダーで利用可能なクラスパス URL を見つける方法を示しています (元の Reflections メソッドは少し簡略化されています)。
public static Set<URL> forClassLoader(ClassLoader... classLoaders) {
final Set<URL> result = Sets.newHashSet();
for (ClassLoader classLoader : classLoaders) {
while (classLoader != null) {
if (classLoader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) classLoader).getURLs();
if (urls != null) {
result.addAll(Sets.<URL>newHashSet(urls));
}
}
classLoader = classLoader.getParent();
}
}
return result;
}
つまり、個々のクラスローダーの URL を求めて、クラスローダー階層をトラバースしています。
Eclipse では、単体テストから前のメソッドを次のように呼び出します。
ClassLoader myClassClassLoader = <MyClass>.class.getClassLoader(); //<MyClass> is in the same classpath url than the resources I need to find
Set<URL> urls = forClassLoader(myClassClassLoader);
for(URL url : urls) {
System.out.println("a url: " + url);
予想どおり、(他の多くの URL の中でも) プロジェクトの一部として構成されているクラスパス URL を確認できます。
file:<MY_PROJECT_PATH>/target/classes/
file:<MY_PROJECT_PATH>/target/test-classes/
Reflections はチャームとして機能します (Reflections が見つけるリソースは にありますfile:<MY_PROJECT_PATH>/target/classes/
)。
しかし、Maven でテストを実行すると、これらの URL エントリがforClassLoader
メソッドによって返されたセットに含まれていないことに気付きました。また、残りの Reflections メソッドがこの問題に対して期待どおりに機能していません。
「驚くべき」ことは、単体テストがmavenによって実行されたときにこれを書くと:
ClassLoader myClassClassLoader = <MyClass>.class.getClassLoader();
url = myClassClassLoader.getResource("anExistingResource");
System.out.println("URL: "+url); //a valid URL
検索しようとしているリソースをクラスローダーが引き続き解決できることがわかります。Maven で実行したときforClassLoader
に、返されたプロジェクトのクラスパス URL のセットにメソッドが含まれないのはなぜでしょうか。同時に、そのような URL にあるリソースを解決することもできます (!)。
この動作の理由は何ですか? Maven によって実行される単体テストの一部として呼び出されたときに Reflections ライブラリを機能させるために試みることができる回避策はありますか?