Load properties file in JAR?
JavaMaven 2ResourcesPropertiesClassloaderJava Problem Overview
I'm having trouble when one of the jars that my web app depends on tries to load a properties file from within the jar. Here is the code in the jar.
static
{
Properties props = new Properties();
try
{
props.load(ClassLoader.getSystemResourceAsStream("someProps.properties"));
} catch (IOException e)
{
e.printStackTrace();
}
someProperty = props.getProperty("someKey");
}
The properties file is in my "src/main/resources" directory of the Maven project. When I run this code from my junit test in Eclipse, it executes just fine. When the project is built with Maven into a jar, and included as a dependency in my web app, it fails to locate the properties file. I know that the properties file is at the base directory of the depended on jar, I don't know how to fix this.
Java Solutions
Solution 1 - Java
The problem is that you are using getSystemResourceAsStream
. Use simply getResourceAsStream
. System resources load from the system classloader, which is almost certainly not the class loader that your jar is loaded into when run as a webapp.
It works in Eclipse because when launching an application, the system classloader is configured with your jar as part of its classpath. (E.g. java -jar my.jar will load my.jar in the system class loader.) This is not the case with web applications - application servers use complex class loading to isolate webapplications from each other and from the internals of the application server. For example, see the tomcat classloader how-to, and the diagram of the classloader hierarchy used.
EDIT: Normally, you would call getClass().getResourceAsStream()
to retrieve a resource in the classpath, but as you are fetching the resource in a static initializer, you will need to explicitly name a class that is in the classloader you want to load from. The simplest approach is to use the class containing the static initializer,
e.g.
[public] class MyClass {
static
{
...
props.load(MyClass.class.getResourceAsStream("/someProps.properties"));
}
}
Solution 2 - Java
For the record, this is documented in How do I add resources to my JAR? (illustrated for unit tests but the same applies for a "regular" resource):
> To add resources to the classpath for
> your unit tests, you follow the same
> pattern as you do for adding resources
> to the JAR except the directory you
> place resources in is
> ${basedir}/src/test/resources
. At
> this point you would have a project
> directory structure that would look
> like the following:
>
> my-app
> |-- pom.xml
> -- src > |-- main > | |-- java > | |
-- com
> | | -- mycompany > | |
-- app
> | | -- App.java > |
-- resources
> | -- META-INF > | |-- application.properties >
-- test
> |-- java
> | -- com > |
-- mycompany
> | -- app > |
-- AppTest.java
> -- resources >
-- test.properties
>
> In a unit test you could use a simple
> snippet of code like the following to
> access the resource required for
> testing:
>
> ...
>
> // Retrieve resource
> InputStream is = getClass().getResourceAsStream("/test.properties" );
>
> // Do something with the resource
>
> ...