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?
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.