如何将源添加到Java构建?

问题描述 投票:0回答:1

我正在开发一个 IntelliJIdea 插件,我需要在构建中添加一个文件 - 该插件必须在使用过程中将此文件复制到用户的源文件夹中。

我将此文件放在

/resources
文件夹中,并且该文件存在于构建中(在相应的 .jar 文件中),但我无法获取该文件的路径。

我尝试获取构建文件夹的路径,但在所有情况下我都会收到

null

class ImageUtils{
   private void m() {
       InputStream resourceAsStream = new ImageUtils().getClass().getResourceAsStream("commonImg.png");
       URL classResource = ImageUtils.class.getClass().getResource("ImageUtils.class");
       URL imageResource = ImageUtils.class.getClass().getResource("");
       URL systemResource = ClassLoader.getSystemResource("");
       URL location = ImageUtils.class.getClass().getProtectionDomain().getCodeSource().getLocation();
   }
}

哪种方式实现这样的逻辑是正确的?

java
1个回答
0
投票

您正在寻找的是:

ImageUtils.class

此表达式的类型为

java.lang.Class<ImageUtils>
,引用代表 ImageUtils 类的 j.l.Class 对象。该对象有一个
getResourceAsStream
方法。

ImageUtils.class.getClass()

ImageUtils.class
返回
java.lang.Class
的实例。因此调用
getClass()
会返回代表
java.lang.Class
本身的 java.lang.Class
 实例 
- 显然这不好。

正确的做法是

ImageUtils.class.getResourceAsStream

ImageUtils.class.getClass().getResource("");

事实并非如此。资源不是目录,也不是文件系统。您只能询问实际的“文件” - 您不能询问目录或根目录等。如果你尝试这样做,在类路径、加载器和 JVM 的某些组合上可以工作,但在其他组合上则不行:这是一个非常非常可怕的错误:一个你无法测试的错误,因此会在你身上失败很多后来,一个错误需要一周的时间才能修复,因为您需要在应用程序中重写大量基础设施。因此,正确的答案绝对是尝试去那里。 如果您需要“列出此“目录”中的所有条目”的概念,您

无法使用类加载器抽象来做到这一点

。相反,使用 SPI:在编译时(通过使用注释处理器或构建系统插件之类的东西,甚至只是手动维护此文件),您创建一个具有众所周知名称的文件,其中列出了列表中的每个项目。然后,您使用 getResourceAsStream 加载此文件,读取它,然后

getResourceAsStream
其中的每个相关项目; Tada,我们确实“列出了所有内容”,但没有命令/API 来“列出所有内容”。
Java本身就使用了这个原理,其中的load-the-list部分是烘焙在

ServiceLoader

中的。


不起作用

ImageUtils.class.getResource("ImageUtils.class")

会起作用 - 但这不是你尝试过的事情之一。 j.l.Class 实例上的

getResource
/
getResourceAsStream
方法
相对于类所在的包
。换句话说,假设 ImageUtils 的顶部有
package com.foo.hhrzc;
getResource("commonImg.png")
将在 jar 文件中查找名为
/com/foo/hhrzc/commonImg.png
的条目。
只需以前导斜杠开头您的资源即可告诉加载器系统:我想从类路径根目录查找。因此,请求 

.getResourceAsStream("/commonImg.png")

- 这将在您的 ImageUtils.class 所在的同一个 jar 中查找,查找名为

/commonImg.png
的条目。 (这就是为什么只要求
"ImageUtils.class"
就有效 - 当然,它就在
/com/foo/hhrzc/ImageUtils.class
的罐子里)。
注意事项:

由于愚蠢的原因,文件名中不能有多个点。
  • ClassLoader
  • 实例也有这些
    getResource
    getResourceAsStream
    方法,但它们是开箱即用的“绝对”(从根部看),事实上,如果您以前导斜杠开始,它们总是会失败。这会导致混乱:如果您想从根目录查看,则必须为
    j.l.Class.getResource
    添加一个前导斜杠,但如果在
    j.l.ClassLoader
    上调用该方法,则不得使用斜杠。在类加载器上使用这些方法几乎总是比仅在类上使用它们更糟糕。加载已知资源的规范、最简单、最惯用、最通用(如每次都有效,没有奇怪的例外)的方法是使用语法:
    SomeClass.class.getResource("resourceName")
    ,其中resourceName,如果是绝对的,需要以斜杠开头。
    
        
© www.soinside.com 2019 - 2024. All rights reserved.