Loading resources in Java always was a little risky. This Blog is about the different ways how resources can be loaded. It contains a test class proving that the mechanism didn't change in Java 9, although resources can not be loaded across module boundaries any more (my next Blog will be about this).
A resource denotes a file that may be packed into the JAR archive representing a Java application, be it a web or a desktop app. Normally you load a Java resource through a file path or name and an anchor class. Consider following example files and directories:
The files root.properties
and resources/package.properties
are example resources. For this demo they can be empty. We will use the class resources/ResourceAnchor.java
to load them.
Resources that do not belong to a specific class often are stored in the root directory of the project. Example is root.properties
. Here is the standard way how to load it:
URL url = ResourceAnchor.class.getResource("/root.properties");
Alternatively you can fetch also an InputStream
, the mechanism is the same:
InputStream inputStream = ResourceAnchor.class.getResourceAsStream("/root.properties");
You can use any class for loading such resources.
Because we want to be safe against package moves and renames, we always place a resource in the same package as its using Java class, and we load the resource through that class. Let's assume that package.properties
belongs to ResourceAnchor.java
, so they are in the same package named "resources". (Mind that in a Maven structure they would be in different directories though). Here is the default way to load package.properties
:
URL url = ResourceAnchor.class.getResource("package.properties");
Or:
InputStream inputStream = ResourceAnchor.class.getResourceAsStream("package.properties");
Class.getResource(resourcePath)
will work on both the filesystem and inside a packed application JAR.
Some people prefer to load resources through the class-loader, not the class, which makes it more difficult to understand:
URL url = ResourceAnchor.class.getClassLoader().getResource("resources/package.properties");
All variants shown until now would work, but you see that this variant is quite strange, as it uses "resources/package.properties" as path, which seems to point to a sub-directory "resources" below the "resources" directory where the anchor class is. Nevertheless this variant works, although I would strongly discourage it. There is no need to use the class-loader for loading resources.
We see that a lot of combinations is possible (and unfortunately also used) for loading resources:
The following test class may help those that are confused and want to know what each of these combinations does. It can also be used to find out behavior changes between different Java versions (there ain't any until now).
1 | package resources; |
Wherever you see checkThat(classResource(".....") != null)
it means success, while checkThat(classResource(".....") == null)
denotes failed resource loading.
If you build such a project and run the resources.ResourceAnchor
class, you will see following output:
Trying to load a root resource:
getClass().getResource("/root.properties"): found
getClass().getResource("root.properties"): missing
getClass().getClassLoader().getResource("/root.properties"): missing
getClass().getClassLoader().getResource("root.properties"): found
Trying to load a package resource:
getClass().getResource("package.properties"): found
getClass().getResource("/resources/package.properties"): found
getClass().getResource("resources/package.properties"): missing
getClass().getClassLoader().getResource("package.properties"): missing
getClass().getClassLoader().getResource("/resources/package.properties"): missing
getClass().getClassLoader().getResource("resources/package.properties"): found
Try this out with Java 1.8 and Java 9 (10, 11), you will see that all succeed and output the same result.
Don't load resources through the class-loader, this gives a wrong impression of the actual location of the file.
ɔ⃝ Fritz Ritzberger, 2020-05-03