6

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 ) **

Krushnat Khavale
  • 416
  • 2
  • 4
  • 14
  • If you are able to run the application on the commandline I assume that your file is really in the jar, so it might be the "\\" signs? I read my classpathresources with "/" also on windows. – the hand of NOD Aug 20 '18 at 11:36
  • @thehandofNOD Indeed, file is present in Jar and I fixed \\, still won't work. – Krushnat Khavale Aug 20 '18 at 21:07

3 Answers3

11

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.

the hand of NOD
  • 1,639
  • 1
  • 18
  • 30
3

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

Alien
  • 15,141
  • 6
  • 37
  • 57
2

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");

....

VC2019
  • 427
  • 1
  • 5
  • 9