'Docker: Can't read class path resource from spring boot application

Reading a classpath resource as,

    try {
        final ClassPathResource classPathResource = new ClassPathResource(format("location%sGeoLite2-City.mmdb", File.separator));
        final File database = classPathResource.getFile();
        dbReader = new DatabaseReader.Builder(database).build();
    } catch (Exception e) {
        System.out.println("Exception: " + e);
    }

I've packaged this with docker using following Dockerfile,

FROM java:8
ADD build/libs/*.jar App.jar
CMD java -jar App.jar

But while running this application as docker run -p 8080:8080 app-image I can hit the application endpoint and from application logs I can see it fails to read this file (following is from logs),

Exception: java.io.FileNotFoundException: class path resource [location/GeoLite2-City.mmdb] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/App.jar!/BOOT-INF/classes!/location/GeoLite2-City.mmdb

Would appreciate any comment, Things to know before you comment,

**- Running on windows 10, intellij 2018.2, jdk 8
- Can run application successfully with intellij as well as command line - File exists in jar (I did extract jar and checked ) **



Solution 1:[1]

It is not a good approach to use slashes.

Always use File Seperators as they work irrespective of System OS.

Change

(location\\GeoLite2-City.mmdb)

to

("location"+ File.separator +"GeoLite2-City.mmdb")

Refer this for more.

https://www.journaldev.com/851/java-file-separator-separatorchar-pathseparator-pathseparatorchar

Difference between File.separator and slash in paths

Solution 2:[2]

Since you are using springboot you can try to use the following annotation for loading your classpath resource. Worked for me because I had the same exception. Be aware that the directory "location" must be under the src/main/resources folder:

@Value("classpath:/location/GeoLite2-City.mmdb")
private Resource geoLiteCity;

Without springboot you could try:

try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("/location/GeoLite2-City.mmdb")) {
... //convert to file and other stuff
}

Also the answers before were correct as the use of "/" is not good at all and File.separator would be the best choice.

Solution 3:[3]

Had the same issue, the file worked when running the Spring boot app but was not working in Docker. My issue got resolved by using ClassPathResource for the resource and reading the resource as stream using InputStreamReader.

Resource resource = new ClassPathResource("test-xyz.json");
InputStream inputStream = null;
        try {
            inputStream = resource.getInputStream();
            Reader reader = new InputStreamReader(inputStream, "UTF-8");

....

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alien
Solution 2 the hand of NOD
Solution 3 VC2019