我正在使用 Google Reflections 库来查询类路径中的某些资源。这些资源与我项目中的类位于同一位置。
我编写了一些在 Eclipse 中作为单元测试执行时成功的单元测试,但是当我尝试使用 Maven(maven install
例如)执行它们时,它们没有按预期工作。经过一番调试,显然问题是用Maven执行时,Reflections库找不到资源所在的classpath url。
我得出了这个结论,研究反射如何确定应该检查的类路径 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 库工作的任何解决方法吗?