Search code examples
javaspringherokuspring-boot

Using ResourceUtils.getFile to read a file from classpath in Heroku environment


I'm running a Spring Boot application in Heroku, using Maven to manage the build lifecycle.

During the initialisation phase of my application, I want to read a file packaged into my JAR file.

To manage to get the content of the file I'm using the Spring utility class ResourceUtils, and I'm expressing the path of the file using the special prefix classpath:.

The code I'm using looks like this:

String pathToMyFile = "classpath:com/myapp/myFile.test"
List<String> fileLines = Files.readLines(ResourceUtils.getFile(pathToMyFile), IOConstants.DEFAULT_CHARSET_TYPE);

This code works as expected when I execute the application in my local machine.

But when I push my application to Heroku I'm getting the following error:

Caused by: java.io.FileNotFoundException: class path resource [com/myapp/myFile.test] 
cannot be resolved to absolute file path because it does not reside in the 
file system: jar:file:/app/target/myapp.jar!/com/myapp/myFile.test 

I've run a heroku run bash and I've checked that the file is just where it should be (inside the jar).

Moreover, according to the error trace, Spring locates the file, because it transform the path from classpath:com/myapp/myFile.test to jar:file:/app/target/myapp.jar!/com/myapp/myFile.test


Solution

  • I suspect that when you are running locally, it is picking up the file on the classpath from an exploded JAR file (i.e. as a regular file on the filesystem).

    On Heroku, it is in the JAR file, which means it is not a regular file, and must be read as an input stream, which might look like this:

    ClassLoader cl = this.getClass().getClassLoader();
    InputStream inputStream = cl.getResourceAsStream(pathToMyFile);
    

    Then you might use a BufferedReader to read the lines. But maybe ResourceUtils has a better method.

    You can probably reproduce the problem locally by running the same command that's in your Profile.