Accessing resource files from external modules
// to scan the module path
ClassLoader.getSystemResources(resourceName)
// if you know a class where the resource is
Class.forName(className).getResourceAsStream(resourceName)
// if you know the module containing the resource
ModuleLayer.boot().findModule(moduleName).getResourceAsStream(resourceName)
See a working example below.
Given:
.
├── FrameworkCore
│ └── src
│ └── FrameworkCore
│ ├── com
│ │ └── framework
│ │ └── Main.java
│ └── module-info.java
└── PlaygroundApi
└── src
└── PlaygroundApi
├── com
│ └── playground
│ └── api
│ └── App.java
├── config.yml
└── module-info.java
Main.java
could be
package com.framework;
import java.io.*;
import java.net.URL;
import java.util.Optional;
import java.util.stream.Collectors;
public class Main {
public static void main( String[] args )
{
// load from anywhere in the modulepath
try {
URL url = ClassLoader.getSystemResources("config.yml").nextElement();
InputStream is = url.openStream();
Main.read(is);
} catch (IOException e) {
throw new RuntimeException(e);
}
// load from the the module where a given class is
try {
InputStream is = Class.forName("com.playground.api.App").getResourceAsStream("/config.yml");
Main.read(is);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
// load from a specific module
Optional<Module> specificModule = ModuleLayer.boot().findModule("PlaygroundApi");
specificModule.ifPresent(module -> {
try {
InputStream is = module.getResourceAsStream("config.yml");
Main.read(is);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
private static void read(InputStream is) {
String s = new BufferedReader(new InputStreamReader(is)).lines().collect(Collectors.joining("\n"));
System.out.println("config.yml: " + s);
}
}
And you would launch with
java --module-path ./FrameworkCore/target/classes:./PlaygroundApi/target/classes \
--add-modules FrameworkCore,PlaygroundApi \
com.framework.Main
To clone this example: git clone https://github.com/j4n0/SO-46861589.git
While you are using the java
command to launch an application as follows:-
java -p target/classes:target/dependency -m framework.core/com.framework.Main
you are specifying the modulepath using the option
-p
aternate for--module-path
which would look up into target/classes and target/dependency for your modules.Alongside, using
-m
alternate for--module
specifies the initial module to resolve with the nameframework.core
and constructs the module graph with the main class to execute explicitly listed ascom.framework.Main
.
Now, the problem here seems to be that the module framework.core
doesn't requires
or read playground.api
module because of which the module graph doesn't include the desired module consisting of the actual resource config.yml
.
As suggested by @Alan, a good way to list out the module resolution output during startup is to make use of the --show-module-resolution
option.
I just naively tried to opens src/main/resources, doesn't compile ofc
Since the resource in your module is at the root level, it is, therefore, not encapsulated and does not need to be opened or exported to any other module.
In your case, you just need to make sure that the module playground.api
ends up in the module graph and then the resource would be accessible to the application. To specify root modules to resolve in addition to the initial module, you can make use of the --add-modules
option.
Hence the overall solution to work for you along with some debugging shall be :
java --module-path target/classes:target/dependency
--module framework.core/com.framework.Main
--add-modules playground.api
--show-module-resolution