为什么添加模块信息后Java无法读取同一个资源文件?

Why Java cannot read same resource file when module-info is added?

有一个具有标准 Maven 文件夹结构的简单 Java 项目。

src
  main
    java
      mypackage
        Main.java
    resource
      abc
        cde.txt  

Main.java(样板省略)

var path = "abc/cde.txt";
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);

if (input == null) {
    throw new IllegalStateException("Resource not found");
} else {
   // read from input
}

此代码工作正常并从绝对路径读取文件
"%project_root%/target/classes/abc/cde.txt"(编译后的代码)。

添加文件src/main/java/module-info.java后情况发生变化:程序找不到文件并抛出in branch (input == null).

如何以旧方式从“资源”文件夹中读取文件并在资源文件夹中同时拥有:java-模块和资源?我想避免在任何地方添加前缀 "src/main/resources"

你可能想要这个:

InputStream input = Main.class.getResourceAsStream("/abc/cde.txt");

当您添加模块-info.java 时,您的 class 被 Java 视为 module

模块的封装限制超出了普通旧 classpath 的限制。要访问模块中的资源,其他代码必须通过该模块,这将检查调用代码的模块是否有权读取这些资源。

ClassLoader.getResourceAsStream will only read resources from explicitly opened modules:

Additionally … this method will only find resources in packages of named modules when the package is opened unconditionally.

但是Class.getResource and Class.getResourceAsStream只依赖class所属的模块,没有那个额外的限制

应始终使用 Class.getResource 或 Class.getResourceAsStream。应避免使用 ClassLoader 等价物。

Class 方法和 ClassLoader 方法之间有一个重要的区别:Class 方法将参数视为相对于 class 的包, 除非参数以斜线开头 (/).

除了封装限制,给定一个名为com.example.MyApplication的class,这两行是等价的:

MyApplication.class.getResource("data.txt")
MyApplication.class.getClassLoader().getResource("com/example/data.txt")

这些是等价的:

MyApplication.class.getResource("/data.txt")
MyApplication.class.getClassLoader().getResource("data.txt")

同样,它们只是在资源路径方面是等价的;模块化封装限制相同。始终使用 Class.getResource* 方法,避免使用 ClassLoader.getResource* 方法。