0

I've created a maven based java project which has resources directory (src/java/resources) and in it some xml files and maven copies them into target/classes/resources (target/classes is my classpath).

To know the content of an xml file, I use:

new FileInputStream(Main.class.getClassLoader().getResource("Configuration.xml").getPath());

Main.class.getClassLoader().getResource("Configuration.xml").getPath() gives me the full path of the xml: "c:\project...\Configuration.xml".

This works well on intellij.

but when I compile and package the project into a jar file I get:

Exception in thread "main" java.io.FileNotFoundException: 
file:\C:\project\target\project-12.50.14-SNAPSHOT-jar-with-dependencies
.jar!\Configuration.xml 

(The filename, directory name, or volume label syntax is incorrect)

That because the path: \C:\project\target\project-12.50.14-SNAPSHOT-jar-with-dependencies .jar!\Configuration.xml cannot be a parameter into FileInputStream().

I cannot replace the getResource() to getResourceAsStream().

I need a way to adjust my jar and resources to work like it work on intellij. I also change the xml resources files content during run-time so that is another problem with keeping them inside a jar.

Can anyone offer me a solution in which I don't have to change me code, and instead change my resources directory structure, or change the classpath, or something else that will keep my code working? Thanks.

Matoy
  • 1,738
  • 3
  • 22
  • 53
  • 5
    "I cannot replace the getResource() to getResourceAsStream()" - why not? Fundamentally, you *can't* use a `FileInputStream` to get at a file embedded within a jar file. You should refactor your code appropriately so that you *can* use `getResourceAsStream`. – Jon Skeet Aug 27 '15 at 15:22
  • why do you need to use FileInputStream? – wero Aug 27 '15 at 15:23
  • I cant replace it because this is not my code. I can only consume this class not change it. in addition - I also change connection.xml during run time, so I prefer that this file will site outside the jar (like the directory on intellij "target/class/connection.xml" – Matoy Aug 27 '15 at 15:30
  • Ah, I see -- this is a question about building / packaging, not about programming. – Thomas Aug 27 '15 at 15:34
  • It appears Intellij puts the directory containing Configuration.xml in the classpath, but when you package the project into a jar, you only have the jar in the classpath. You would need to extract Configuration.xml and make sure it's directory is ahead of the jar on the runtime classpath. – tdrury Aug 27 '15 at 15:59

1 Answers1

0

Update: Changed to use File, not Path.

That is because getResource returns a URL, and not all urls are files on disk, i.e. can be converted to a Path. As javadoc says "Returns [...] an empty string if [path part] does not exist".

If it absolutely must be a File or FileInputStream, because some other code you cannot change requires it, then copy the content to a temporary file:

File file = File.createTempFile("Configuration", ".xml");
try {
    try {InputStream in = Main.class.getClassLoader().getResourceAsStream("Configuration.xml")) {
        Files.copy(in, file.toPath()); // requires Java 7
    }
    // use file here, or:
    try {FileInputStream in = new FileInputStream(file)) {
        // use file stream here
    }
} finally {
    file.delete();
}

The above code could be optimized to not copy if resource is a file, but since that's only for development mode, and production mode is always a Jar and will always need the copy, using copy in development mode helps test the code.

Andreas
  • 154,647
  • 11
  • 152
  • 247