6

故意破坏以下代码以识别 NullPointerException 的来源,这本来应该非常简单,但结果让我抓狂:

Properties properties = new Properties();
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
InputStream propertiesStream = contextClassLoader.getResourceAsStream("resource.properties");
if (propertiesStream != null) {
  properties.load(propertiesStream);
  // TODO close the stream
} else {
  // Properties file not found!
}

我得到“找不到属性文件!” 错误,即 contextClassLoader.getResourceAsStream("resource.properties"); 返回 null

这是一个基于 CXF 的客户端,我验证了“resource.properties”文件位于客户端 jar 所在(并运行)的当前目录中。

我还通过包含以下诊断代码验证了绝对路径:

            File file = new File("resource.properties");
            System.out.println(file.getAbsolutePath());

绝对路径指向客户端的 jar 所在的位置。

我还尝试使用以下方法找出类加载器的上下文:

  System.out.println(Thread.currentThread().getContextClassLoader());

但是这里展示了一些目录结构,我得到的只是:

com.simontuffs.onejar.JarClassLoader@1decdec

为什么 ClassLoader.getResourceAsStream() 会返回 null?

我错过了什么?

4

2 回答 2

10

我解开了这个谜。

解决的关键是在为空 嵌入一些诊断日志记录:propertiesStream

String classpath = System.getProperty("java.class.path");
LOG.info("CLASSPATH: " + classpath);
ClassLoader loader = MyClientMain.class.getClassLoader();
System.out.println("ClassLoader resource path: " + loader.getResource("resource.properties"));                    

所以当我用原版运行时

contextClassLoader.getResourceAsStream("resource.properties")

我收到空指针条件,打印:

  INFO: CLASSPATH: myproj.one-jar.jar
  ClassLoader resource path: null

.

然后我开始怀疑与“jar 中的 jar”相关的东西,因为这就是com.simontuffs.onejar本质上所做的(即将我的项目的 jar 包装在一个包含所有其他库 jar 的 jar 中),所以我打开了 myproj.one-带有 7-Zip 的 jar.jar 并记下“resource.properties”的完整(绝对)路径:

myproj.one-jar.jar\main\myproj.jar\webapp\WEB-INF\classes\resource.properties

.

所以我修改getResource("resource.properties")为:

 getResource("/main/myproj.jar/webapp/WEB-INF/classes/resource.properties")

这没有解决问题,但在空指针条件下打印了以下内容:

INFO: CLASSPATH: myproj.one-jar.jar
ClassLoader resource path: jar:file:/myproj.one-jar.jar!/main/myproj.jar!//main/myproj.jar/webapp/WEB-INF/classes/resource.properties

.

然后......神圣的干预降临到我身上,我有洞察力(我发誓没有阅读任何可能暗示这一点的文档!)我应该使用这条路径:

 getResource("/webapp/WEB-INF/classes/resource.properties")

瞧!有用。

唷。

于 2014-04-10T14:50:52.300 回答
2

正如 EJP 指出的那样,这意味着资源不能通过这个特定类加载器的类路径获得(不同的类加载器可以有不同的类路径)。

由于类加载器是一个JarClassLoader,它只能加载包含jar 文件中的资源。它不会看到与 jar 文件位于同一目录中的文件。

于 2014-04-09T18:54:05.997 回答