Car*_*ala 13 java junit classloader getresource
我正在为一个需要在初始化期间加载配置文件的项目创建一个JUnit TestCase.
此配置文件位于src/main/resources/config文件夹中的项目内,并且在构建maven期间将其放入JAR内的/ config文件夹中.
初始化类,使用以下语句从那里读取文件:
ClassLoader classloader = this.getClass().getClassLoader();
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(classLoader.getResourceAsStream("/config/config.xml")));
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,当我将这个jar部署并执行到应用程序服务器时,它按预期工作,但是,每当我在Eclipse中的JUnit TestCase中运行它时,getResrouceAsStream方法返回null.
考虑到该类是my.package.MyClassTest.java,并且它位于src/test/java/my/package/MyClassTest.java中,我已经尝试将config.xml文件的副本放入以下文件夹中但没有成功:
- src/test/resources/config
- src/test/resources/my/package/config
- src/test/java/my/package/config
Run Code Online (Sandbox Code Playgroud)
我知道在StackOverflow中已经多次询问过类似的问题,但是我发现的所有响应都指的是改变文件的加载方式,虽然更改代码可能是一个选项,但我更愿意找到合适的地方.该文件所以我不需要修改已经在生产环境中工作的东西.
那么,我应该在哪里放置这个文件,以便能够在我的JUnit测试中使用它?
UPDATE
我只是通过对代码进行一些小改动来提出解决方案:我没有使用ClassLoader来获取资源,而是直接使用了类:
Class clazz = this.getClass();
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(clazz.getResourceAsStream("/config/config.xml")));
Run Code Online (Sandbox Code Playgroud)
它从src/test/resources/config/config.xml成功读取文件.
但是,这里有一些非常奇怪的东西:Class.getResourceAsStream方法是:
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
Run Code Online (Sandbox Code Playgroud)
如果我调试它,我可以清楚地看到这个getClassLoader0()返回与前一个调用完全相同的对象(相同的id),this.getClass().getResourceAsStream()(我维护,只是为了比较值)! !
这里发生了什么?!
为什么在工作之间插入新方法调用时直接调用方法不起作用?
老实说,我对此非常惊讶.
顺便说一句,我使用的是JUnit 4.10版.可能以某种方式篡改getClassLoader调用吗?
非常感谢,
普约尔
Rea*_*tic 17
回答你的问题
如果我调试它,我可以清楚地看到这个getClassLoader0()返回与前一个调用完全相同的对象(相同的id),this.getClass().getResourceAsStream()(我维护,只是为了比较值)! !
这里发生了什么?!
为什么在工作之间插入新方法调用时直接调用方法不起作用?
呼唤之间的区别
this.getClass().getClassLoader().getResourceAsStream("/config/config.xml");
Run Code Online (Sandbox Code Playgroud)
并打电话
this.getClass().getResourceAsStream("/config/config.xml");
Run Code Online (Sandbox Code Playgroud)
位于您显示的确切来源Class
:
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
Run Code Online (Sandbox Code Playgroud)
但问题不在于什么getClassLoader0()
回报.它在两种情况下都返回相同的内容.实际上差别在于resolveName(name)
.这是Class
该类中的私有方法.
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/')
+"/"+name;
}
} else {
name = name.substring(1);
}
return name;
}
Run Code Online (Sandbox Code Playgroud)
所以你看,在实际调用classLoader之前getResourceAsStream()
,它实际上从路径中删除了起始斜杠.
一般情况下,它会尝试获取相对于this
没有斜杠的资源,如果它在开头有斜杠,则将其传递给classLoader.
classLoader的getResourceAsStream()
方法实际上是用于相对路径(否则你只需要使用a FileInputStream
).
所以当你使用时this.getClass().getClassLoader().getResourceAsStream("/config/config.xml");
,你实际上是在路径中用斜杠传递它,但是失败了.当你使用this.getClass().getResourceAsStream("/config/config.xml");
它时,它足够友好地为你删除它.