Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing resource files from external modules

Tags:

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?

like image 665
cen Avatar asked Oct 21 '17 08:10

cen


People also ask

How do I retrieve files from resources folder?

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().

What is the use of getResourceAsStream in Java?

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.


1 Answers

// 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

like image 81
Jano Avatar answered Dec 21 '22 03:12

Jano