Friday, March 6, 2015

Accessing resource files within JARs

There were two items I needed to access:
  1. A keystore (.jks) file that contains a third-party certificate;
  2. A text file within a separate JAR file added as a library as part of the WAR package for the project.
Accessing the keystore file
The resources I'd found (like this one), all point to the same place. Using the calling class, reference a relative path to where the resource is located:

getClass().getResourceAsStream("../resources/keystore.jks");

This will work as long it is according to the Java package structure. In order to better understand where my class is calling from exactly, I'd output this to the server log:

getClass().getResourceAsStream(".");
This will show you the full absolute path to the Java class file you've been working with, on the server.

The JKS file can then be accessed like this:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream keyStoreFile = getClass().getResourceAsStream(keyStorePath);
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());

Accessing the text file in a JAR
This resource is slightly trickier. Mostly because it is contained within a separate JAR file. But don't worry, there is no need to use JarFile for this. My project was already using Maven, and has a pom.xml for packaging. But because this JAR does not contain any Java source files, it doesn't belong in the repository. I had to manually add it to the WAR file classpath by modifying the pom.xml file.

I added this snippet to the section meant for maven-war-plugin:
<archive>
  <manifest>
    <addClasspath>true</addClasspath>
    <classpathPrefix>lib/</classpathPrefix>
  </manifest>
  <manifestEntries>
    <Class-Path>lib/target.jar</Class-Path>
  </manifestEntries>
</archive>

Separately, in the calling Java class, note that the earlier getClass().getResourceAsStream("."); does not work in this instance. This is because the class is in a different JAR file. Instead, according to this, you need to make use of its ClassLoader like so:

getClass().getClassLoader().getResourceAsStream("file.txt"));

Note that file.txt is in the root of the target.jar file, but because target.jar has already been added to the WAR classpath, its contents is immediately visible to the ClassLoader of the same WAR file.

You can then read it like any normal text file:

BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream(path)));

That is all. Have fun!

No comments:

Post a Comment