java - Acceso a archivos de recursos desde módulos externos
java-9 jigsaw (2)
Hasta ahora, hasta que Java no esté modularizado, simplemente debe colocar un archivo en
src/main/java/resources
para asegurarse de que esté en classpath y luego cargarlo con
file = getClass().getClassLoader().getResourceAsStream("myfilename");
desde prácticamente cualquier parte del classpath.
Ahora con módulos, la trama se complica.
La configuración de mi proyecto es la siguiente:
module playground.api {
requires java.base;
requires java.logging;
requires framework.core;
}
El archivo de configuración se coloca dentro de
src/main/resources/config.yml
.
El proyecto se ejecuta con
java -p target/classes:target/dependency -m framework.core/com.framework.Main
Como la clase principal no reside en mi propio proyecto, sino en un módulo de marco externo, no puede ver
config.yml
.
Ahora la pregunta es, ¿hay alguna manera de poner de alguna manera mi archivo de configuración en el módulo o abrirlo?
¿Tengo que cambiar la forma en que el archivo se carga en el marco ascendente?
Traté de usar "exportaciones" o "abre" en la información del módulo, pero quiere tener un nombre de paquete, no un nombre de carpeta.
¿Cómo lograr esto de la mejor manera práctica para que funcione como en Java 8 y con la menor cantidad de cambios posible?
Mientras usa el comando
java
para iniciar una aplicación de la siguiente manera: -
java -p target/classes:target/dependency -m framework.core/com.framework.Main
-
está especificando el modulepath usando la opción
-palternativa para--module-pathque buscaría en target / classes y target / dependency para sus módulos. -
Además, el uso de
-malternativo para--moduleespecifica el módulo inicial para resolver con el nombreframework.corey construye el gráfico del módulo con la clase principal para ejecutar explícitamente comocom.framework.Main.
Ahora, el problema aquí parece ser que el módulo
framework.core
no
requires
o lee el módulo
playground.api
debido a que el gráfico del módulo no incluye el módulo deseado que consiste en el recurso real
config.yml
.
Según lo
sugerido por @Alan
, una buena manera de enumerar la salida de resolución del módulo durante el inicio es utilizar la opción
--show-module-resolution
.
Intenté ingenuamente abrir src / main / resources, no compila ofc
Dado que el recurso en su módulo está en el nivel raíz , por lo tanto, no está encapsulado y no necesita abrirse ni exportarse a ningún otro módulo.
En su caso, solo necesita asegurarse de que el módulo
playground.api
termine en el gráfico del módulo y luego el recurso sea accesible para la aplicación.
Para especificar los módulos raíz a resolver además del módulo inicial, puede utilizar la opción
--add-modules
.
Por lo tanto, la solución general para trabajar para usted junto con alguna depuración será:
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)
Vea un ejemplo de trabajo a continuación.
Dado:
.
├── 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
podría ser
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);
}
}
Y lanzarías con
java --module-path ./FrameworkCore/target/classes:./PlaygroundApi/target/classes /
--add-modules FrameworkCore,PlaygroundApi /
com.framework.Main
Para clonar este ejemplo:
git clone https://github.com/j4n0/SO-46861589.git