Introduction

When creating a Spring Boot web app, it is sometimes necessary to load files from the classpath, for example if data is only available as a file. In my case I was using a MAXMIND GeoLite2 database for geolocation retrieval. Therefore I needed to load the file and create a DatabaseReader object, which is stored in the server memory.

Beneath you will find the solutions for loading files in a WAR and JAR.

The ResourceLoader

With Java you can use the classLoader of the current thread and try to load the file, but the Spring Framework provides you with much more elegant solution like the ResourceLoader.

You just need to autowire the ResourceLoader and then call the getResource(„somePath“) method.

Example of loading a file from the resource directory / classpath in Spring Boot (WAR)

In the following example we are loading a file called GeoLite2-Country.mmdb from the classpath as a resource and after that retrieving it as a File object.

@Service("geolocationservice")
public class GeoLocationServiceImpl implements GeoLocationService {

    private static final Logger LOGGER = LoggerFactory.getLogger(GeoLocationServiceImpl.class);

    private static DatabaseReader reader = null;

    private ResourceLoader resourceLoader;

    @Autowired
    public GeoLocationServiceImpl(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @PostConstruct
    public void init() {
        try {
            LOGGER.info("GeoLocationServiceImpl: Trying to load GeoLite2-Country database...");

            Resource resource = resourceLoader.getResource("classpath:GeoLite2-Country.mmdb");
            File dbAsFile = resource.getFile();

            // Initialize the reader
            reader = new DatabaseReader
                        .Builder(dbAsFile)
                        .fileMode(Reader.FileMode.MEMORY)
                        .build();

            LOGGER.info("GeoLocationServiceImpl: Database was loaded successfully.");

        } catch (IOException | NullPointerException e) {
            LOGGER.error("Database reader cound not be initialized. ", e);
        }
    }

    @PreDestroy
    public void preDestroy() {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                LOGGER.error("Failed to close the reader.");
            }
        }
    }
}

Load file from Spring Boot JAR

If you would like to load a file from classpath in a Spring Boot JAR, then you have to use the resource.getInputStream() method to retrieve it as a InputStream. If you try to use resource.getFile() you will receive an error, because Spring tries to access a file system path, but it can not access a path in your JAR.

@Service("geolocationservice")
public class GeoLocationServiceImpl implements GeoLocationService {

    private static final Logger LOGGER = LoggerFactory.getLogger(GeoLocationServiceImpl.class);

    private static DatabaseReader reader = null;
    private ResourceLoader resourceLoader;

    @Inject
    public GeoLocationServiceImpl(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @PostConstruct
    public void init() {
        try {
            LOGGER.info("GeoLocationServiceImpl: Trying to load GeoLite2-Country database...");

            Resource resource = resourceLoader.getResource("classpath:GeoLite2-Country.mmdb");
            InputStream dbAsStream = resource.getInputStream(); // <-- this is the difference

            // Initialize the reader
            reader = new DatabaseReader
                        .Builder(dbAsStream)
                        .fileMode(Reader.FileMode.MEMORY)
                        .build();

            LOGGER.info("GeoLocationServiceImpl: Database was loaded successfully.");

        } catch (IOException | NullPointerException e) {
            LOGGER.error("Database reader cound not be initialized. ", e);
        }
    }

    @PreDestroy
    public void preDestroy() {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                LOGGER.error("Failed to close the reader.");
            }
        }
    }
}