在另一个模块中获取资源的 URL

Getting The URL of Resource in Another Module

我正在编写一个库来简化 JavaFX 应用程序的开发,并且为了使其可用于 Java 模块化系统,我需要获得 URL另一个 java 模块(客户端模块)中的 FXML 文件并将其传递到我的库(库模块)中的 FXMLLoader

总而言之: 我需要在客户端模块中获取 FXML 文件的资源 URL,以便在库模块中读取。

我试过了:

Load a Resource from another Module in Java (With Maven)

我最近的尝试:

private void addController(ControllerInfo info, Class<? extends SimpleController> controllerClass) throws IOException {
        String filename = info.FXMLFile();
        if (!filename.startsWith("/"))
            filename = "/" + filename;
        ModuleReference ref=ModuleLayer.boot().configuration().findModule(moduleName).map(ResolvedModule::reference).get();
        ModuleReader resReader=ref.open();

        URL url = resReader.find(filename).get().toURL();

        controllerClasses.put(info.Id(), controllerClass);
        info.Type().getAction().addController(info, url, controllerClass);
    }

在客户端模块中,我将资源放在资源文件夹中的 io/github/ossnass/languageexample 文件夹中,module-info.java 如下所示:

module languageExample {
    requires javafx.controls;
    requires javafx.fxml;
    requires simplefx;
    opens io.github.ossnass.languageexample.gui to javafx.fxml;
    opens io.github.ossnass.languageexample to simplefx;
    exports io.github.ossnass.languageexample.app;
}

FXML 控制器 class:

@ControllerInfo(Id = "LangMain", FXMLFile = "/io/github/ossnass/languageexample/langexample.fxml", Type = ContollerType.SINGLE_INSTANCE_ON_STARTUP)
public class LangExampleMain extends SimpleController {
    @Override
    protected void userInit() {

    }

    @Override
    protected void onStageShowUser() {

    }

    @FXML
    private Button btnMessage;

    @FXML
    void btnMessageClick(ActionEvent event) {
        QuickActions.showInfoMessage(null,
                resources.getString("InfoHeader"),
                resources.getString("InfoBody"),
                this);
    }
}

我收到以下错误:

java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication(LauncherImpl.java:195)
        at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.util.NoSuchElementException: No value present
        at java.base/java.util.Optional.get(Optional.java:148)
        at io.github.ossnass.fx.ControlMaster.addController(ControlMaster.java:179)
        at io.github.ossnass.fx.ControlMaster.findControllers(ControlMaster.java:198)
        at io.github.ossnass.fx.ControlMaster.initControlMaster(ControlMaster.java:134)
        at io.github.ossnass.languageexample.app.Main.start(Main.java:11)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1(LauncherImpl.java:846)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait(PlatformImpl.java:455)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:428)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:427)
        at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
        at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop(GtkApplication.java:277)
        ... 1 more

资源文件的URL路径是:/io/github/ossnass/languageexample/langexample.fxml

请注意,我正在使用 Maven,并将 FXML 放在 resources 目录中。

我正在开发的库可以在 SimpleFX

找到

在如何从 VGR

正确制作 URL 的帮助下,我能够使用 ClassGraph 库解决问题

以下代码解决了所有问题(Java 8 和 Java 9+ 使用模块化系统):

    public static Resource getRescoure(String urlStr) {
        try (ScanResult scan = new ClassGraph().scan()) {
            if (urlStr.startsWith("/"))
                urlStr = urlStr.substring(1);
            ResourceList rl = scan.getResourcesWithPath(urlStr);
            if (rl.size() > 0)
                return rl.get(0);
            return null;
        }
    }