0

I have the following situation:

  • JAR A has JAR B as dependency
  • JAR B is packed with some resources that are loaded when JAR A calls specific methods of JAR B (loaded once and for all the lifecycle of JAR B calls)
  • I am using Java SE 11 with IntelliJ 2021.1.3

JAR B resources tree is something like the following:

 - resources
     - data
         - file.txt
     - tariffs
         - folder1
             - file.xslx

Resources are loaded through the following method:

private InputStream getPath(String nomeFile) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        return classLoader.getResourceAsStream(DATA_FOLDER_NAME.concat(File.separator).concat(nomeFile));
}

And then managed through a BufferedReader.

Everything works fine when running mvn test (or application tests) withing JAR B project or when consuming JAR B from JAR A in a Unix environment. When consuming JAR B from JAR A in a Windows 10 environment the getPath method returns a null InpuStream object thus a NullPointerException from the BufferedReader:

java.lang.NullPointerException: null
    at java.base/java.io.Reader.<init>(Reader.java:167)
    at java.base/java.io.InputStreamReader.<init>(InputStreamReader.java:72)
    ...

I tried to change the File.separator to hardcoded "/" in the method and seems like everything works also on Windows, but is failing in other places (where resources are managed) since I suppose Paths need to be hand-fixed.

I tried to change the loader to: this.getClass().getResourcesAsStream(...) and other workaround with no luck.

My question is: is there a way to make the program work as expected also on Windows without changing the above code? Are there any settings I am missing?

Thank you, Alberto

AlSteve
  • 65
  • 1
  • 9
  • Sounds like an elaborate way of describing your classpath is wrong ;) All needed jars need to be on it. Note `-jar` negates any external (to the jar) classpath. How are you attempting to run it? – g00se Jul 26 '21 at 10:10
  • Can you post the value of DATA_FOLDER_NAME, It looks like an issue with the start op the path or with the relative path construction – Javier Toja Jul 26 '21 at 10:10
  • Hi @g00se , when running from IJ I use the Debug feature (or Run) in _Run/Debug configuration_ ; while outside IJ I am running it through `java -jar JARA.jar`. Being a Maven project I am using the assembly plugin to pack all dependencies in JAR A, isn't it correct? And, beside this: why this is only occuring in a Win environment? – AlSteve Jul 26 '21 at 10:23
  • Hi @karelss the value of that variable is the String `data` . – AlSteve Jul 26 '21 at 10:24
  • @AlSteve try putting a slash before. like /data/... https://stackoverflow.com/questions/941754/how-to-get-a-path-to-a-resource-in-a-java-jar-file – Javier Toja Jul 26 '21 at 10:32
  • *I am running it through java -jar JARA.jar* So are you using maven-shade-plugin? – g00se Jul 26 '21 at 10:36
  • @karelss no luck adding the leading "/" unfortunately – AlSteve Jul 26 '21 at 10:47
  • @g00se no I am using maven-jar-plugin + maven-assembly plugin currently. I also tried using the shade plugin but the problem is still the same. – AlSteve Jul 26 '21 at 10:50
  • @AlSteve when i had this errors in the past they always come from the using relative or full paths that in windows change, with relative paths you should be fine using the getClass().getResource, i suggest that you try in a windows environment with a test to check the proper path configuration, all of this outside intellij with the mvn test – Javier Toja Jul 26 '21 at 10:51
  • *@g00se no I am using maven-jar-plugin…* Then you need to re-read my comment above. You need to provide the proper classpath – g00se Jul 26 '21 at 10:55
  • A tip: *never* run apps through IDEs - it's wholly artificial and will conceal problems that you'll face when running them properly. – g00se Jul 26 '21 at 11:03
  • @karelss thank you, will give a try on a test environment and let you know. I agree on the usage of the getResource, in fact it seems odd to me that this is not working correctly. – AlSteve Jul 26 '21 at 12:26
  • @karelss posted the solution below – AlSteve Jul 26 '21 at 12:51

2 Answers2

2

Just came over this issue. The fact was (and is) the usage of File.separator in a Windows environment to access resources inside a JAR.

This is because (as pointed here) inside a JAR file paths are resolved UNIX-style.

The only way, then, to consume resources that are packed within a JAR file used as dependency is to specify resources paths UNIX-style.

In my case, this mean replacing the File.separator (and all occurrences) with a "/".

The other issues that were arising by this replacement were due to an incomplete replace-all of the File.separator directive across the code.

AlSteve
  • 65
  • 1
  • 9
0
java -classpath A.jar;B.jar x.y.z.Main

Would be what your command to run would look like on Windows. Possibly better to use the absolute path to those jars for fail-proof ops

g00se
  • 3,207
  • 2
  • 5
  • 9
  • ok and thank you, will give a try using the -cp command launching the main class of the application (that is in A.jar) – AlSteve Jul 26 '21 at 12:28
  • g00se: posted the solution below, seems like the `File.separator` is not to be used when referencing resources packed inside another JAR. – AlSteve Jul 26 '21 at 12:52
  • Yes, resource paths are URLs and so the only separator is `/` NB my answer is in reponse to your *I am running it through java -jar JARA.jar.* which won't work even if your separators *are* correct – g00se Jul 26 '21 at 13:14