I am trying to use Maven to build a JAR file that will load files from the file system during runtime. I am having an issue with loading the file after compiling it with
mvn clean package
pom.xml:
<build>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>7</source>
<target>7</target>
</configuration>
</plugin>
</plugins>
</build>
My main Class is:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class App {
public static void main(String[] args) throws IOException {
App app = new App();
app.printTestFile();
}
public void printTestFile() throws IOException {
File file = new File(getClass().getClassLoader().getResource("template.txt").getFile());
System.out.println("File is in " + file.getAbsolutePath());
printFile(file);
}
private static void printFile(File file) throws IOException {
try (FileReader reader = new FileReader(file);
BufferedReader br = new BufferedReader(reader)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
}
The file is loaded with:
File file = new File(getClass().getClassLoader().getResource("template.txt").getFile());
The project structure is:
│ pom.xml
└───src
├───main
│ ├───java
│ │ App.java
│ └───resources
│ template.txt
└───test
└───java
When run with IntelliJ the result is:
File is in C:\Users\user\Documents\Git\maven-scratch\target\classes\template.txt
This is the test file's content.
However, the issue comes when run purely with Maven like:
mvn clean package
java -jar target\maven-scratch-1.0-SNAPSHOT.jar
Outputs the error:
File is in C:\Users\user\Documents\Git\maven-scratch\file:\C:\Users\user\Documents\Git\maven-scratch\target\maven-scratch-1.0-SNAPSHOT.jar!\template.txt
Exception in thread "main" java.io.FileNotFoundException: file:\C:\Users\user\Documents\Git\maven-scratch\target\maven-scratch-1.0-SNAPSHOT.jar!\template.txt (The filena
me, directory name, or volume label syntax is incorrect)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileReader.<init>(Unknown Source)
at App.printFile(App.java:19)
at App.printTestFile(App.java:15)
at App.main(App.java:9)
The thing that puzzles me the most is that the file that's trying to be loaded has the path:
C:\Users\user\Documents\Git\maven-scratch\file:\C:\Users\user\Documents\Git\maven-scratch\target\maven-scratch-1.0-SNAPSHOT.jar!\template.txt
... whether with IntelliJ the path is:
C:\Users\user\Documents\Git\maven-scratch\target\classes\template.txt
Is there an easy way to use a file from Maven's resources folder and after packaging into a JAR with Maven to also be able to read the file from the target directory?
The JAR construction is fine (easily verified by loading it into a zip file viewer).
IntelliJ's classpath is the local filesystem - it is loading a real file ./target/classes/template.txt
Commandline classpath is looking for the same thing inside the JAR file (maven-scratch-1.0-SNAPSHOT.jar!\template.txt
). This is not an actual file itself, it is some bytes inside the JAR file. Basically it can't be read by FileReader
which is looking for a file literally named maven-scratch-1.0-SNAPSHOT.jar!\template.txt
// getResourceAsStream doesn't care if it comes from a real file or a jar
InputStream is = getClass().getClassLoader().getResourceAsStream("fix.cfg");
InputStreamReader reader = new InputStreamReader(is);