Jusqu'à présent, jusqu'à Java non modularisé, vous mettriez simplement un fichier dans src/main/Java/resources
assurez-vous qu'il se trouve dans le chemin d'accès aux classes, puis chargez-le avec
file = getClass().getClassLoader().getResourceAsStream("myfilename");
à peu près n'importe où dans le chemin de classe.
Maintenant, avec les modules, l'intrigue s'épaissit.
La configuration de mon projet est la suivante:
module playground.api {
requires Java.base;
requires Java.logging;
requires framework.core;
}
Le fichier de configuration est placé à l'intérieur de src/main/resources/config.yml
.
Le projet est exécuté avec
Java -p target/classes:target/dependency -m framework.core/com.framework.Main
Puisque la classe principale ne réside pas dans mon propre projet, mais dans un module de framework externe, elle ne peut pas voir config.yml
. Maintenant, la question est, existe-t-il un moyen de mettre en quelque sorte mon fichier de configuration dans le module ou de l'ouvrir? Dois-je changer la façon dont le fichier est chargé par le framework en amont?
J'ai essayé d'utiliser "exports" ou "opens" dans module-info mais il veut avoir un nom de package, pas un nom de dossier.
Comment y parvenir de la meilleure façon possible pour que cela fonctionne comme dans Java 8 et avec le moins de changements possible?
Pendant que vous utilisez la commande Java
pour lancer une application comme suit: -
Java -p target/classes:target/dependency -m framework.core/com.framework.Main
vous spécifiez le modulepath en utilisant l'option -p
alternative pour --module-path
qui rechercherait cible/classes et cible/dépendance pour vos modules.
Parallèlement, en utilisant -m
alternatif pour --module
spécifie le module initial à résoudre avec le nom framework.core
et construit le graphe du module avec la classe principale à exécuter explicitement répertoriée comme com.framework.Main
.
Maintenant, le problème semble être que le module framework.core
ne fait pas requires
ou ne lit pas playground.api
module à cause duquel le graphique du module n'inclut pas le module souhaité composé de la ressource réelle config.yml
.
Comme suggéré par @Alan , un bon moyen de lister la sortie de résolution du module au démarrage est d'utiliser le --show-module-resolution
option.
J'ai juste naïvement essayé d'ouvrir src/main/resources, ne compile pas ofc
Puisque la ressource dans votre module est au niveau racine , elle est donc non encapsulée et n'a pas besoin d'être ouvert ou exporté vers un autre module.
Dans votre cas, il vous suffit de vous assurer que le module playground.api
finit dans le graphe du module et la ressource serait alors accessible à l'application. Pour spécifier les modules racine à résoudre en plus du module initial, vous pouvez utiliser le --add-modules
option.
Par conséquent, la solution globale à travailler pour vous avec un débogage sera:
Java --module-path target/classes:target/dependency
--module framework.core/com.framework.Main
--add-modules playground.api
--show-module-resolution
// 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)
Voir un exemple de travail ci-dessous.
Donné:
.
├── 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
pourrait être
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);
}
}
Et vous lancez avec
Java --module-path ./FrameworkCore/target/classes:./PlaygroundApi/target/classes \
--add-modules FrameworkCore,PlaygroundApi \
com.framework.Main
Pour cloner cet exemple: git clone https://github.com/j4n0/SO-46861589.git