为什么 Jenkins 无法加载资源?

14

这是我的项目布局:

src/
  test/
    resources/
        ares/
          file1.xml
          file2.xml

这是 Jenkins 工作区的布局:

 my-module/
   target/
     test-classes/
       ares/
         file1.xml
         file2.xml

在 Eclipse 下,测试运行没有任何错误。 在 Jenkins 下,测试失败了。Jenkins 无法定位资源。 以下是测试执行的一些输出:

Eclipse

MyClass.class.getResourceAsStream(/ares/file1.xml) => java.io.BufferedInputStream@4f4b2f1a
MyClass.class.getResourceAsStream(ares/file1.xml) => null

Thread.currentThread().getContextClassLoader().getResourceAsStream(/ares/file1.xml) => null
Thread.currentThread().getContextClassLoader().getResourceAsStream(ares/file1.xml) => java.io.BufferedInputStream@5d402eeb

MyClass.class.getClassLoader().getResourceAsStream(/ares/file1.xml) => null
MyClass.class.getClassLoader().getResourceAsStream(ares/file1.xml) => java.io.BufferedInputStream@20c87621

Jenkins

MyClass.class.getResourceAsStream(/ares/file1.xml) => null
MyClass.class.getResourceAsStream(ares/file1.xml) => null

Thread.currentThread().getContextClassLoader().getResourceAsStream(/ares/file1.xml) => null
Thread.currentThread().getContextClassLoader().getResourceAsStream(ares/file1.xml) => null

MyClass.class.getClassLoader().getResourceAsStream(/ares/file1.xml) => null
MyClass.class.getClassLoader().getResourceAsStream(ares/file1.xml) => null

正如您所看到的,Jenkins找不到我的资源。

我缺少什么?


不同的行为可能是由于在Eclipse中使用m2e插件和Jenkins使用其系统配置中指定的(本机)Maven。我也看到过使用m2e与本机Maven安装之间的差异。我总是将_Eclipse首选项_ → Maven → _安装_从_EMBEDDED_更改为本机。然而,你为什么要在POM中声明 <testResources>目录呢?无论如何,默认值为src/test/resources - Gerold Broser
@GeroldBroser 我声明了,因为我认为 Maven 不会在“src/test/resources”中包含子目录。 - Stephan
请尝试在删除<testResources>部分后,在Jenkins上构建该项目并向我们展示结果。 - Stefan Birkner
@StefanBirkner 我刚刚运行了没有<testResources>部分的构建。结果与我的问题中的一样:\ - Stephan
你是否检查了Jenkins上的作业工作区,确认文件确实存在且放置在正确的位置? - Gerold Broser
@GeroldBroser 文件放在了正确的位置。 - Stephan
3个回答

14

我终于解决了我的问题。在类路径上,文件名为/ares/file1.xml,而在我的代码中,我调用的文件名为/ares/file1.XML。你是否注意到大写的XML了?

在Windows上,没有区别,因为文件名不区分大小写。在Linux上,它会失败,因为文件名区分大小写。

最后的想法是,当你在不同于目标平台的平台上编码时,请使用小写文件名。


14

我曾遇到一个类似但原因不同且解决方案不同的问题。

我的情况是Jenkins服务器是Windows机器,位于资源位置的完整路径以空格开始,例如C:\Program Files (x86)\...。如果您需要使用new File(getClass().getResource(fileName).getFile())将其作为File而不是流获取,这些空格将被编码为%20。这里的fileName是包含资源名称的字符串。我通过添加对URLDecoder.decode的调用来解决问题。当没有空格或者您不在Windows上(据我所见)时,这不会造成任何问题,但是如果在名称中得到一个空格,则可以解决该问题。完整的调用如下:

 new File(URLDecoder.decode(getClass().getResource(fileName).getFile(), "UTF-8"))

我从几个问题中整合了这个答案,但没有一个将所有内容都整合到Jenkins的情况下,因此在此回答。其他相关问答:


如果可能的话,我将不使用File,而是使用getResourceAsStream()通过InputStream获取资源。除了URL转义的问题外,该资源甚至可能不是文件系统中的文件:它可能被压缩在类路径上的JAR文件中。大多数接受File的API也会接受InputStream,从长远来看,这将节省与文件路径相关的许多麻烦。 - raner

1
自从我在混乱中度过半天后两次来到这里解决了我的问题,我想我应该添加我的解决方案以帮助未来的旅行者。
Jenkins作业名称中的空格将破坏Java项目中资源文件的加载。除非您专门编写不同的加载代码来取悦Jenkins。
我已经将其简化为一条非常沮丧的建议:不要在Java项目的Jenkins作业名称中放置空格。
你可以总结几个要点...
首先,如果您在Jenkins作业的名称中放置空格,则Jenkins不会隐藏该空格。因此,将作业命名为"My Awesome New Job",路径变为/home/jenkins/My%Awesome%New%20Job 第二,如果您的资源路径中有%20,则您的代码将需要对资源路径进行URL解码才能加载资源。就像这个答案所说的那样:https://dev59.com/61sX5IYBdhLWcg3whv7Q#43269197 在我的情况下,这些资源文件仅用于测试,因此我只是用连字符替换了作业名称中的空格。

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