14

Here is the layout of my project:

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

Here is the layout of the Jenkins workspace:

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

Under eclipse the tests run without any error. On Jenkins, the tests just fail. Jenkins is unable to locate the resources. Below are some output from the test execution:

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

As you can see Jenkins doesn't find my resource.

What am I missing?

Stephan
  • 41,764
  • 65
  • 238
  • 329
  • The different behaviour can be due to using the m2e plugin when within Eclipse and Jenkins using the (native) Maven specified in its system config. I've seen differences between using m2e vs. the native Maven installation, too. I always change _Eclipse Preferences_ → _Maven_ → _Installations_ from _EMBEDDED_ to a native. However, why do you declare [the `` directory](https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html) in your POM at all? The [default is `src/test/resources`](https://maven.apache.org/pom.html#Resources) anyway. – Gerold Broser Nov 13 '15 at 13:14
  • @GeroldBroser I declare because I thought Maven wouldn't include subdirectories in `src/test/resources`. – Stephan Nov 13 '15 at 14:37
  • Could you try to build the project on Jenkins after removing the section and show us the results. – Stefan Birkner Nov 13 '15 at 15:06
  • @StefanBirkner I just ran the build without the section. The results are the same as in my question :\ – Stephan Nov 13 '15 at 15:09
  • Have you checked the job's workspace on Jenkins whether the file is really there and at the right place? – Gerold Broser Nov 13 '15 at 15:30
  • @GeroldBroser The file is at the right place. – Stephan Nov 13 '15 at 15:53

3 Answers3

14

I finally solved my issue. On the classpath, the file is named /ares/file1.xml while in my code I was calling the file /ares/file1.XML. Did you notice the uppercased XML?

On Windows, there is no difference since filenames are case insensitive. On Linux, it fails because filenames ARE case sensitive.

Final thought, when you code on a platform different from the target platform prefer lower case filenames.

Stephan
  • 41,764
  • 65
  • 238
  • 329
14

I had this problem with similar symptoms but different cause and different solution.

In my case the issue was that the Jenkins server was a Windows machine and the full path on the server to the location of the resources started with C:\Program Files (x86)\... with spaces. Those spaces get encoded to %20 if you need to get is as a File instead of a stream using new File(getClass().getResource(fileName).getFile()). Here fileName is a string that contains the name of the resource. I solved the problem by adding a call to URLDecoder.decode. This creates no problems when there are no spaces or you're not on Windows (as far as I've seen) but it solves the problem if you get a space in the name somewhere along the line. The full call is then:

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

I pieced this together from several questions, but none put it all together for the Jenkins case, hence my answer here. Other relevant Q&A:

Community
  • 1
  • 1
Brick
  • 3,998
  • 8
  • 27
  • 47
  • If at all possible, I would not use a `File` at all, but instead use an `InputStream` via `getResourceAsStream()`. In addition to the problems with URL escaping, the resource may not even be a file in the file system: it could be a zipped up in a JAR that's on the class path. Most APIs that accept `File`s will accept `InputStream`s as well, and in the long run it will save a lot of headache related to file paths. – raner Dec 11 '20 at 00:15
1

Since I got here twice before I solved my problem after half a day of confusion I thought I'd add what was my solution to help a future traveller.

Spaces in job names on Jenkins will break the loading of resource files in Java projects. Unless you specifically write your loading code differently just to appease Jenkins.

I have boiled this down to one very frustrated piece of advice: DO NOT PUT SPACES IN JENKINS JOB NAMES FOR JAVA PROJECTS.

You can put together a couple of points...

One, if you put a space in the name of a jenkins job then jenkins does no fangling to hide that space. So call your job "My Awesome New Job" and the path to the job becomes /home/jenkins/My%Awesome%New%20Job

Two, if your resource path has %20 in it then your code will need to URL decode the resource path in order to be able to load the resource. As in this other answer that got me there: https://stackoverflow.com/a/43269197/222163

In my situation these resource files are only for tests so I just replaced the space in my job name with a hyphen.

Paul D'Ambra
  • 7,629
  • 3
  • 51
  • 96