Java allows the retrieval of file-based resources stored inside of a JAR alongside compiled classes. This topic focuses on loading those resources and making them available to your code.
A resource is file-like data with a path-like name, which resides in the classpath. The most common use of resources is bundling application images, sounds, and read-only data (such as default configuration).
Resources can be accessed with the ClassLoader.getResource and ClassLoader.getResourceAsStream methods. The most common use case is to have resources placed in the same package as the class which reads them; the Class.getResource and Class.getResourceAsStream methods serve this common use case.
The only difference between a getResource method and getResourceAsStream method is that the former returns a URL, while the latter opens that URL and returns an InputStream.
The methods of ClassLoader accept a path-like resource name as an argument and search each location in the ClassLoader’s classpath for an entry matching that name.
The resource name is similar to the path portion of a relative URL. On all platforms, it uses forward slashes (/
) as directory separators. It must not start with a slash.
The corresponding methods of Class are similar, except:
For instance:
package com.example;
public class ExampleApplication {
public void readImage()
throws IOException {
URL imageURL = ExampleApplication.class.getResource("icon.png");
// The above statement is identical to:
// ClassLoader loader = ExampleApplication.class.getClassLoader();
// URL imageURL = loader.getResource("com/example/icon.png");
Image image = ImageIO.read(imageURL);
}
}
Resources should be placed in named packages, rather than in the root of a .jar file, for the same reason classes are placed in packages: To prevent collisions among multiple vendors. For example, if multiple .jar files are in the classpath, and more than one of them contains a config.properties
entry in its root, calls to the getResource or getResourceAsStream methods will return the config.properties from whichever .jar is listed first in the classpath. This is not predictable behavior in environments where the classpath order is not under the direct control of the application, such as Java EE.
All getResource and getResourceAsStream methods return null
if the specified resource does not exist. Since resources must be added to the application at build time, their locations should be known when the code is being written; a failure to find a resource at runtime is usually the result of programmer error.
Resources are read-only. There is no way to write to a resource. Novice developers often make the mistake of assuming that since the resource is a separate physical file when developing in an IDE (like Eclipse), it will be safe to treat it like a separate physical file in the general case. However, this is not correct; applications are almost always distributed as archives such as .jar or .war files, and in such cases, a resource will not be a separate file and will not be writable. (The getFile method of the URL class is not a workaround for this; despite its name, it merely returns the path portion of a URL, which is by no means guaranteed to be a valid filename.)
There is no safe way to list resources at runtime. Again, since the developers are responsible for adding resource files to the application at build time, developers should already know their paths. While there are workarounds, they are not reliable and will eventually fail.