如何在Java 9中使用类加载器访问资源

6

我在eclipse中有一个gradle项目。以下是我的项目结构:

project structure

我有一个CSS资源文件styleclass.cssscr/main/resources/css目录下。首先我尝试通过以下方式来访问它:

scene.getStylesheets().add("css/styleclass.css"); 

但是我收到了“资源未找到”的警告。我也尝试删除“module-info.java”文件,但结果仍然相同。

然后我尝试使用

String urlString = ComboBoxStyling.class.getClassLoader().getResource("css/styleclass.css").toExternalForm();

问题是,如果我移除moduele-info.java和应用样式表,这行代码可以工作。但是在使用module-info.java时,我遇到了空指针异常。
我不是很清楚,但至少我知道在Java 9中类加载器发生了变化。那么我该如何在Java 9中做同样的事情呢?我的module-info.java文件包含以下内容。
module pk.training.basit {
    exports pk.training.basit;
    requires transitive javafx.controls;
}

感谢与问候
Basit Mahmood Ahmed

8
该资源已封装,因此无法使用ClassLoader API找到。我认为ComboBoxStyling.class.getResource("/css/styleclass.css")会起作用 - 请注意前导斜杠,以便相对于模块的根位置找到它,而不是相对于ComboBoxStyling.class。 - Alan Bateman
是的,那个可以工作 :) - Basit
1
请发布您的答案,以便我可以接受它。 - Basit
1
https://dev59.com/c1YN5IYBdhLWcg3wza94 - Oleksandr Pyrohov
2个回答

3

来自 ClassLoader.getResource JavaDoc 的内容:

命名模块中的资源受Module.getResourceAsStream指定的封装规则的约束。此外,除了资源名称以“.class”结尾的特殊情况外,当打开包时(即使调用此方法的调用者与资源位于同一模块中),此方法仅在命名模块的包中查找资源。

因此,要解决您的问题,您应该使css包打开:

module pk.training.basit {
    exports pk.training.basit;
    requires transitive javafx.controls;
    opens css;
}

原始问题似乎是代码试图定位自己的资源。ClassLoader API 不是用于此目的的正确 API。如果将代码更改为在模块中调用类上的 getResource,则应该可以正常工作,无需打开任何包。 - Alan Bateman
1
@AlanBateman 我只是准确回答了提问者的问题。如果他有200个地方使用getClassLoader().getResource()怎么办?那么他只需要添加一行代码,而不必更改这200个地方。 - ZhekaKozlov

2

您应该将CSS文件放在与使用它的类相同的包中,然后使用Class.getResource以相对路径访问它。

src/main/java:
  pk.training.basit
    ComboBoxStyling.java

src/main/resources:
  pk.training.basit
    ComboBoxStyling.css

然后在源代码中:

scene.getStylesheets().add(
  ComboBoxStyling.class.getResource("ComboBoxStyling.css").toExternalForm());

个人认为将CSS和类放在同一个目录中甚至是更好的做法,然后配置gradle使其可以获取src/main目录中的资源。这样可以拥有类似于其他GUI产品(如Angular)的架构,将屏幕的所有资源,包括源代码,都放在同一个目录中,例如如果您有一个FXML文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接