Java Language Finding and reading resources using a classloader


Example

Resource loading in Java comprises the following steps:

  1. Finding the Class or ClassLoader that will find the resource.
  2. Finding the resource.
  3. Obtaining the byte stream for the resource.
  4. Reading and processing the byte stream.
  5. Closing the byte stream.

The last three steps are typically accomplished by passing the URL to a library method or constructor to load the resource. You will typically use a getResource method in this case. It is also possible to read the resource data in application code. You will typically use getResourceAsStream in this case.

Absolute and relative resource paths

Resources that can be loaded from the classpath are denoted by a path. The syntax of the path is similar to a UNIX / Linux file path. It consists of simple names separated by forward slash (/) characters. A relative path starts with a name, and an absolute path starts with a separator.

As the Classpath examples describe, a JVM's classpath defines a namespace by overlaying the namespaces of the directories and JAR or ZIP files in the classpath. When an absolute path is resolved, it the classloaders interpret the initial / as meaning the root of the namespace. By contrast, a relative path may be resolved relative to any "folder" in the namespace. The folder used will depend on the object that you use to resolve the path.

Obtaining a Class or Classloader

A resource can be located using either a Class object or a ClassLoader object. A Class object can resolve relative paths, so you will typically use one of these if you have a (class) relative resource. There are a variety of ways to obtain a Class object. For example:

  • A class literal will give you the Class object for any class that you can name in Java source code; e.g. String.class gives you the Class object for the String type.

  • The Object.getClass() will give you the Class object for the type od any object; e.g. "hello".getClass() is another way to get Class of the String type.

  • The Class.forName(String) method will (if necessary) dynamically load a class and return its Class object; e.g. Class.forName("java.lang.String").

A ClassLoader object is typically obtained by calling getClassLoader() on a Class object. It is also possible to get hold of the JVM's default classloader using the static ClassLoader.getSystemClassLoader() method.

The get methods

Once you have a Class or ClassLoader instance, you can find a resource, using one of the following methods:

MethodsDescription
ClassLoader.getResource(path)
ClassLoader.getResources(path)
Returns a URL which represents the location of the resource with the given path.
ClassLoader.getResources(path)
Class.getResources(path)
Returns an Enumeration<URL> giving the URLs which can be used to locate the foo.bar resource; see below.
ClassLoader.getResourceAsStream(path)
Class.getResourceStream(path)
Returns an InputStream from which you can read the contents of the foo.bar resource as a sequence of bytes.

Notes:

  • The main difference between the ClassLoader and Class versions of the methods is in the way that relative paths are interpreted.

    • The Class methods resolve a relative path in the "folder" that corresponds to the classes package.
    • The ClassLoader methods treat relative paths as if they were absolute; i.e. the resolve them in the "root folder" of the classpath namespace.
  • If the requested resource (or resources) cannot be found, the getResource and getResourceAsStreammethods returnnull, and thegetResourcesmethods return an emptyEnumeration`.

  • The URLs returned will be resolvable using URL.toStream(). They could be file: URLs or other conventional URLs, but if the resource resides in a JAR file, they will be jar: URLs that identify the JAR file and a specific resource within it.

  • If your code uses a getResourceAsStream method (or URL.toStream()) to obtain an InputStream, it is responsible for closing the stream object. Failure to close the stream could lead to a resource leak.