In addition to the existing answers I’d like to give an example of encapsulation rules for non-class-file resources for different resource directory names.
The specification for getResourceAsStream says that the resource is encapsulated if a package name is derived from its name.
So if the resource’s directory name is NOT a valid Java identifier, it is NOT encapsulated. Which means that if a module has a resource located under, for example, a directory named dir-1
(containing a non-valid character -
in its name) it will always be accessible from outside of the module.
Here is an example of two Java modules (source code in GitHub). Module 1 consists of the following resource files:
├── dir-3
│ └── resource3.txt
├── dir1
│ └── resource1.txt
├── dir2
│ └── resource2.txt
└── root.txt
and module-info.java
:
module module_one {
opens dir1;
}
Module 2 requires Module 1 in module-info.java
:
module module_two {
requires module_one;
}
and has a sample main class for loading various resource files:
package module2;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
loadResource("root.txt", "From module's root directory");
loadResource("dir1/resource1.txt", "From opened package `dir1`");
loadResource("dir2/resource2.txt", "From internal package `dir2`");
loadResource("dir-3/resource3.txt", "From directory `dir-3` with non-Java name");
}
public static void loadResource(String name, String comment) throws IOException {
// module2 application class loader
final var classLoader = Main.class.getClassLoader();
try (var in = classLoader.getResourceAsStream(name)) {
System.out.println();
System.out.println("// " + comment);
System.out.println(name + ": " + (in != null));
}
}
}
Running the class above gives the following output:
// From module's root directory
root.txt: true
// From opened package `dir1`
dir1/resource1.txt: true
// From internal package `dir2`
dir2/resource2.txt: false
// From directory `dir-3` with non-Java name
dir-3/resource3.txt: true
As you can see the resource file from the root directory and from the dir-3
directory are not encapsulated, therefore Module 2 can load them.
The package dir1
is encapsulated but unconditionally opened. Module 2 can load it as well.
The package dir2
is encapsulated and not opened. Module 2 cannot load it.
Note that Module 2 cannot contain their own resources under dir1
and dir2
directories because they are already encapsulated in Module 1. If you try adding dir1
you will get the following error:
Error occurred during initialization of boot layer
java.lang.LayerInstantiationException: Package dir1 in both module module_one and module module_two
Here is a Flyway related issue for reference.
module-info.java
isn't supported, but we're still running into walls with the resource loader? Is there any concession for developers looking to play nicely with JRE9 without yet adopting the new JDK9 language level? – Aseity