Why would ClassLoader.getResourceAsStream() return null?

Withheld picture Withheld · Apr 9, 2014 · Viewed 15k times · Source

Having the following code broken deliberately to identify the source of a NullPointerException in something that should have been very simple but turns out to drive me nuts:

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!
}

I get the "Properties file not found!" error, i.e. contextClassLoader.getResourceAsStream("resource.properties"); returns null.

This is a CXF-based client and I verified that the "resource.properties" file is in the current directory in which the client's jar resides (and runs).

I also verified the absolute path by including the following diagnostic code:

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

The absolute path points to where the client's jar is.

I also tried finding out the context of the class loader, using:

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

but instead some directory structure as demonstrated here, all I get is:

com.simontuffs.onejar.JarClassLoader@1decdec

Why would ClassLoader.getResourceAsStream() return null?

What am I missing?

Answer

Withheld picture Withheld · Apr 10, 2014

I solved the mystery.

The key to solving was embedding some diagnostic logging when propertiesStream is null:

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"));                    

So when I run with the original

contextClassLoader.getResourceAsStream("resource.properties")

I receive the null pointer condition, printing:

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

.

I then started suspecting something related to the "jar within a jar" as this is what the com.simontuffs.onejar essentially does (i.e. wrapping my project's jar inside a jar that contains all other library jars), so I opened myproj.one-jar.jar with 7-Zip and noted the full (absolute) path of "resource.properties":

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

.

So I modified getResource("resource.properties") to:

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

which didn't fix the problem but printed the following upon the null pointer condition:

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

.

Then... divine intervention fell upon me and I had the insight (not reading any documentation that could even hint this, I swear!) that I should be using this path instead:

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

And Voila! It works.

Whew.