Java IO - Read file from resources folder reliably in Spring Boot
Read file from resources folder reliable in Spring Boot
Sample implementation: https://github.com/explorer436/programming-playground/tree/main/java-playground/handling-backend-lookups-examples
To reliably get a file from the resources in Spring Boot application:
- Find a way to pass abstract resource, for example,
InputStream
,URL
instead ofFile
- Use framework facilities to get the resource
Avoid using File because it is not always possible to get it from a classpath resource
When we want to read a file from the resources folder in spring boot, we need to use resource.getInputStream()
(and not resource.getFile()
)
mvn clean package && java -jar target/spring-caching-data-from-resource-files-demo-0.0.1-SNAPSHOT.jar
Both of these will work when we are running the application in an IDE. But when we package the jar file and run it from terminal, resource.getFile()
will not work. In that scenario, if we try to read it as a file, we will run into this error: Classpath resource not found when running as jar
java.io.FileNotFoundException: class path resource [IdValuesFile.json] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/home/explorer436/Downloads/GitRepositories/programming-playground/java-playground/spring-caching-data-from-resource-files-demo/target/spring-caching-data-from-resource-files-demo-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/IdValuesFile.json
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:217) ~[spring-core-6.0.11.jar!/:6.0.11]
resource.getFile()
expects the resource itself to be available on the file system, i.e. it can’t be nested inside a jar file. This is why it works when you run your application in IDE but doesn’t work once you’ve built your application and run it from the executable jar. Rather than using getFile()
to access the resource’s contents, use getInputStream()
instead. That’ll allow you to read the resource’s content regardless of where it’s located.
Case sensitivity of the file names
Another important thing to note: When running the application it ignores capitals in file/folders in the resources folder where it doesn’t ignore it while running as a jar.
@Autowired
ApplicationContext appContext;
// this will work when running the application, but will fail when running as jar
appContext.getResource("classpath:testfolder/message.txt");
Therefore, don’t use capitals in your resources or also add those capitals in your constructor of ClassPathResource:
appContext.getResource("classpath:Testfolder/message.txt");
A couple of utility methods
If you want to read resource file as a String, you can use these static utils methods:
public static String getResourceFileAsString(String fileName) {
InputStream is = getResourceFileAsInputStream(fileName);
if (is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
return (String)reader.lines().collect(Collectors.joining(System.lineSeparator()));
} else {
throw new RuntimeException("resource not found");
}
}
public static InputStream getResourceFileAsInputStream(String fileName) {
ClassLoader classLoader = {CurrentClass}.class.getClassLoader();
return classLoader.getResourceAsStream(fileName);
}
Example usage:
String soapXML = getResourceFileAsString("some_folder_in_resources/SOPA_request.xml");