Packaging and accessing run-time resources in a runnable Jar
with credit and gratitude to Stephen Baier and Andrew Arminio (CS477, S09), who did some of the legwork on this


Often times we will work on a Java project where certain resources (e.g. images, sounds, movie clips) will be required by our program at runtime. For compactness, we would like (a) the Java program to be packaged as a runnable Jar, and (b) all resources needed by the program to be packaged neatly inside the jar file. As it turns out, this is simple in in concept, but more than a little tricky to implement in practice. Generally, your runnable jar'ed java program will (when running) simply look locally in the file system for required resource files. One way to make sure they are there is to (manually or automatically) place them there in a folder --- but this is definitely less than elegant. Ideally, your program would simply access the resource files right out of the jar package; this makes complete sense and is in line with the spirit of jar packaging. This tutorial is created to help point you to number of approaches for doing this.

Here is a general overview of what we need to do to achieve our goal:

One question I haven't answered to my satisfaction yet is whether this same modified resource access code will also work during development. The implications from Mr. Baier's experience (see further down) is "no, once you change it, it will only run from Jar", meaning it's the very last modification you want to do before submitting your app. Kind of unfortunate...and doesn't actually make much sense, ie, the class loader should be viable whether or not your running from jar. Wouldn't be the first thing though. I'll try to explore this when I get some free minutes...

The information below is adapted directly from this link; I'm just copying it here in case this link dies. The link was provided by A. Arminio.

Overview of the technique:

Packaging an application and all of its resources in a single runnable Jar file is clean and efficient. However, the technique for successfully accessing images or other resource files inside of the jar from inside your code is not at all self evident --- until you hit on the general principle of how to do it: calling on the class loader for some class you are using (which KNOWS where it's class is .... ie, in the jar file....i.e., this is also where the resource files are) to help you access the desired resource files. Here are a couple of code examples:

Accessing a file as an input stream,
e.g., to load a XML file, you could use the code below. Assume the file "properties.xml" is inside of the "application.jar" file, that is stored in the "conf" package. Here we tell the classloader to return the resource as a stream.

ClassLoader cl = this.getClass().getClassLoader(); in = cl.getResourceAsStream("conf/properties.xml");

Accessing a resource file, e.g., image, sounds, etc.
The code here is just slightly different in that we simply ask the classloader to return us resource file directly. The example below shows how to create an image icon to illustrate the concept.

// When the image file is in the same package of the class 'SearchTab'.
new ImageIcon(SearchTab.class.getResource("magnifyingGlass.png");

// When the image file is in another package of the jar file.
ClassLoader cl = this.getClass().getClassLoader();
JButton btRemove = new JButton(new ImageIcon(cl.getResource("images/remove.png")));

Reading versus Writing.

It does not appear that the Java API provides any way to MODIFY(write to) files inside a Jar file --- it's a read-only container. This does more or less make sense: it's supposed to be an archive, not some sort of database or pseudo-filesystem.

Another take on the same thing

S. Baier found a similar solution to the problem, i.e., still uses the classloader to help find the resources. Just slightly different code. Here is what he came up with:

static ImageIcon squareL;
static ImageIcon squareM;
static ImageIcon squareS;

In class constructor:
URLClassLoader urlLoader=(URLClassLoader)this.getClass().getClassLoader();
squareL = new ImageIcon(urlLoader.findResource("squareL.GIF"));
squareM = new ImageIcon(urlLoader.findResource("squareM.GIF"));
squareS = new ImageIcon(urlLoader.findResource("squareS.GIF"));