Java 9 jigsaw - доступ к файлам ресурсов из внешних модулей
До тех пор, пока не модулярная java, вы просто поместите файл в src/main/java/resources
, убедитесь, что он находится в пути к классам, а затем загрузите его с помощью
file = getClass().getClassLoader().getResourceAsStream("myfilename");
из почти любого места в пути к классам.
Теперь с модулями сюжет сгущается.
Моя настройка проекта следующая:
module playground.api {
requires java.base;
requires java.logging;
requires framework.core;
}
Файл конфигурации помещается внутри src/main/resources/config.yml
.
Проект выполняется с помощью
java -p target/classes:target/dependency -m framework.core/com.framework.Main
Поскольку основной класс не находится в моем собственном проекте, но во внешнем модуле рамки он не может видеть config.yml
. Теперь вопрос в том, есть способ каким-то образом положить мой файл конфигурации в модуль или открыть его? Должен ли я изменить способ загрузки файла фреймворком вверх по течению?
Я попытался использовать "export" или "opens" в модуле info, но он хочет иметь имя пакета, а не имя папки.
Как добиться этого наилучшим образом, чтобы он работал как на Java 8 и с минимальными изменениями?
Ответы
Ответ 1
Пока вы используете команду java
для запуска приложения следующим образом: -
java -p target/classes:target/dependency -m framework.core/com.framework.Main
-
вы указываете путь к модулю с помощью опции -p
aternate для --module-path
, которая будет искать в целевых/классов и цели/зависимости для ваших модулей.
-
Кроме того, использование -m
alternate для --module
указывает начальный модуль для разрешения с именем framework.core
и строит граф модуля с основным классом, чтобы выполнить явно перечисленные как com.framework.Main
.
Теперь проблема заключается в том, что модуль framework.core
не имеет requires
или читает модуль playground.api
, из-за которого графа модуля не включает желаемый модуль, состоящий из фактического ресурса config.yml
.
Как предложенный @Alan, хороший способ отобразить вывод разрешения модуля во время запуска состоит в использовании опции --show-module-resolution
.
Я просто наивно пытался открыть src/main/resources, не компилирует ofc
Поскольку ресурс в вашем модуле находится на уровне root, поэтому он и его не нужно открывать или экспортировать в какой-либо другой модуль.
В вашем случае вам просто нужно убедиться, что модуль playground.api
заканчивается в графе модулей, а затем ресурс будет доступен для приложения. Чтобы указать корневые модули для решения в дополнение к исходному модулю, вы можете использовать опцию --add-modules
.
Следовательно, общее решение для работы с вами вместе с некоторой отладкой должно быть:
java --module-path target/classes:target/dependency
--module framework.core/com.framework.Main
--add-modules playground.api
--show-module-resolution
Ответ 2
// 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)
См. рабочий пример ниже.
Дано:
.
├── 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
может быть
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);
}
}
И вы начнете с
java --module-path ./FrameworkCore/target/classes:./PlaygroundApi/target/classes \
--add-modules FrameworkCore,PlaygroundApi \
com.framework.Main
Чтобы клонировать этот пример: git clone https://github.com/j4n0/SO-46861589.git