So far until non-modularized java, you would simply put a file in src/main/java/resources
make sure it is in classpath and then load it with
file = getClass().getClassLoader().getResourceAsStream("myfilename");
from pretty much anywhere in the classpath.
Now with modules, the plot thickens.
My project setup is the following:
module playground.api { requires java.base; requires java.logging; requires framework.core; }
Config file is placed inside src/main/resources/config.yml
.
Project is run with
java -p target/classes:target/dependency -m framework.core/com.framework.Main
Since the main class does not reside in my own project, but in an external framework module, it can't see config.yml
. Now the question is, is there a way to somehow put my config file into the module or open it up? Do I have to change the way file is loaded by framework upstream?
I tried using "exports" or "opens" in module-info but it wants to have a package name, not a folder name.
How to achieve this in best practical way so it would work as in Java 8 and with as little changes as possible?
In Java, we can use getResourceAsStream or getResource to read a file or multiple files from a resources folder or root of the classpath. The getResourceAsStream method returns an InputStream . // the stream holding the file content InputStream is = getClass(). getClassLoader().
The getResourceAsStream method returns an InputStream for the specified resource or null if it does not find the resource. The getResource method finds a resource with the specified name. It returns a URL to the resource or null if it does not find the resource. Calling java.
// 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With