Java 9 jigsaw-доступ к файлам ресурсов из внешних модулей

до тех пор, пока не модульная Java, вы бы просто положить файл в src/main/java/resources убедитесь, что он находится в пути к классам, а затем загрузите его с помощью

file = getClass().getClassLoader().getResourceAsStream("myfilename"); 

практически везде в classpath.

теперь с модулями, сюжет утолщается.

моя настройка проекта следующая:

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

так как основной класс не проживает в моем собственном проект, но во внешнем модуле framework он не может видеть config.yml. Теперь вопрос в том, есть ли способ каким-то образом поместить мой файл конфигурации в модуль или открыть его? Должен ли я изменить способ загрузки файла платформой вверх по течению?

Я попытался использовать "экспорт" или "открывает" в module-info, Но он хочет иметь имя пакета, а не имя папки.

как достичь этого наилучшим практическим способом, чтобы он работал как в Java 8 и с как можно меньшими изменениями?

2 ответов


при использовании java команда для запуска приложения следующим образом: -

java -p target/classes:target/dependency -m framework.core/com.framework.Main 
  • вы указываете modulepath, используя опцию -p aternate для --module-path который будет смотреть в целевой/классы и целевой/зависимость для ваших модулей.

  • вместе с тем, используя -m Альтернативный для --module указывает начальный модуль для разрешения с именем framework.core и строит график модуля с основным классом для выполнения явно указан как com.framework.Main.

теперь проблема здесь, кажется, в том, что модуль framework.core не requires или читать playground.api модуль, из-за которого график модуля не включает нужный модуль, состоящий из фактического ресурса config.yml.

As предложил @Alan, хороший способ перечислить выход разрешения модуля во время запуска это использовать .


я просто наивно пытался открыть src / main / resources, не компилирует ofc

С ресурсов в свой модуль на корневом уровне, поэтому не инкапсулированные и не нужно быть раскрытым или экспортированным к любому другому модулю.

в вашем случае вам просто нужно убедиться, что модуль playground.api заканчивается в модуле график, а затем ресурс будет доступен для приложения. Чтобы указать корневые модули для разрешения в дополнение к исходному модулю, вы можете использовать .


следовательно, общее решение для работы для вас вместе с некоторой отладкой должно быть:

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)

см. пример ниже.


дано:

.
├── 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