web-dev-qa-db-fra.com

Accès aux fichiers de ressources à partir de modules externes

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?

16
cen

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

6
Jano