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
-p
alternativa para--module-path
que buscaría en target / classes y target / dependency para sus módulos. -
Además, el uso de
-m
alternativo para--module
especifica el módulo inicial para resolver con el nombreframework.core
y 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