Reputation: 7825
There is a simple Java project with standard Maven folder structure.
src
main
java
mypackage
Main.java
resource
abc
cde.txt
Main.java (boilerplate omitted)
var path = "abc/cde.txt";
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
if (input == null) {
throw new IllegalStateException("Resource not found");
} else {
// read from input
}
This code works fine and read file from the absolute path
"%project_root%/target/classes/abc/cde.txt"
(compiled code).
After adding file src/main/java/module-info.java
the situation changes: the program cannot find the file and throws in branch (input == null)
.
How to read files from "resource" folder the old way and have both: java-module and resources in the resource folder? I would like to avoid adding a prefix "src/main/resources"
everywhere.
Upvotes: 1
Views: 1658
Reputation: 44414
You probably want this:
InputStream input = Main.class.getResourceAsStream("/abc/cde.txt");
When you add a module-info.java, your classes are considered a module by Java.
A module has encapsulation restrictions beyond what a plain old classpath has. To access resources in a module, other code must go through that module, which will check whether the calling code’s module has permission to read those resources.
ClassLoader.getResourceAsStream will only read resources from explicitly opened modules:
Additionally … this method will only find resources in packages of named modules when the package is opened unconditionally.
But Class.getResource and Class.getResourceAsStream only rely on the module to which the class belongs, and don’t have that additional restriction.
One should always use Class.getResource or Class.getResourceAsStream. The ClassLoader equivalents should be avoided.
There is an important difference between the Class methods and the ClassLoader methods: The Class methods treat the argument as relative to the class’s package, unless the argument starts with a slash (/
).
Aside from the encapsulation restrictions, given a class named com.example.MyApplication, these two lines are equivalent:
MyApplication.class.getResource("data.txt")
MyApplication.class.getClassLoader().getResource("com/example/data.txt")
And these are equivalent:
MyApplication.class.getResource("/data.txt")
MyApplication.class.getClassLoader().getResource("data.txt")
Again, they are only equivalent in terms of the resource path; the modular encapsulation restrictions are not the same. Always use the Class.getResource* methods, and avoid the ClassLoader.getResource* methods.
Upvotes: 9