How to read a file from the resources folder in a Spring Boot application
This is a quick post that explains how to read a file from the resources folder (Classpath) within a Spring Boot command line application.
Introduction
For applications, I have implemented in the last couple of years, I quite often had the requirement to store additional lookup data within the resource folder of my Maven project. Interestingly, many solutions you will find on the internet will work well in an IDE like Eclipse, STS or IntelliJ, but not when you create a Spring Boot application. The main reason is that IDEs usually can access these resource files from the source or target folder. Though, some approaches don't work if the application is being packaged, for example when using mvn package from the spring-boot-maven-plugin.
To demonstrate a way to read files from the resource folder after packaged, I have created a small command line Spring Boot application that implements the following requirements.
We create a CountryService that returns a list of configured countries - country name and 2-letter ISO code. A country can be looked up by it's ISO code. The list of available countries will be stored as key-value pairs in a properties file. When the application starts up, we read the content of the properties file and store the result internally in a Map.
The code for this post is available in this GitHub repository.
Country properties file
The properties file I use as example stores four countries.
src/main/resources/data/countryCodes.properties
CA=Canada
DE=Germany
UK=United Kingdom
US=United States of America
Country service
Then we create the service interface and implementation in the package com.progressive.code.resource.service
CountryService interface
package com.progressive.code.resource.service;
import java.util.Map;
/**
* Created by abraun on 14/11/2017.
*/
public interface CountryService {
String getCountryByIsoCode(String isoCode);
Map<String,String> getAllCountries();
}
CountryService implementation
Let's focus on the method readCountries() invoked by the constructor.
- First, we create an instance of a Properties object
- Then we create a ClassPathResource (from the Spring core.io package), using the location of the properties file within the resource folder
- The ClassPathResource class allows us to read the properties based on an InputStream
- And finally, we use forEach to iterate through the properties and store the ISO code as key and the country name as value within the HashMap
package com.progressive.code.resource.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Created by abraun on 14/11/2017.
*/
@Service
public class CountryServiceImpl implements CountryService {
private static final Logger LOGGER = LoggerFactory.getLogger(CountryServiceImpl.class);
private static final String COUNTRY_DATA = "data/countryCodes.properties";
private final Map<String, String> countries = new HashMap<>();
public CountryServiceImpl() {
readCountries();
LOGGER.info("Loaded {} countries", countries.keySet().size());
}
@Override
public String getCountryByIsoCode(String isoCode) {
return countries.get(isoCode);
}
@Override
public Map<string, string> getAllCountries() {
return countries;
}
/**
* This method reads the country codes properties file from the resource
* folder (ClassPath) and stores the result in a HashMap.
*/
private void readCountries() {
try {
//Instantiate a new Properties object
Properties props = new Properties();
//Create a ClassPathResource, based on the given location within the resource folder
ClassPathResource res = new ClassPathResource(COUNTRY_DATA);
//Load the properties using InputStream provided by the ClassPathResource
props.load(res.getInputStream());
//Map the properties to the HashMap
props.stringPropertyNames().forEach(
isoName -> countries.put(isoName, props.get(isoName).toString())
);
} catch (IOException e) {
//For this example just log the exception
LOGGER.error("Exception occurred while trying to read {}", COUNTRY_DATA, e);
}
}
}
Create a JUnit Test
Let's create a JUnit test to ensure that everything works as expected.
CountryServiceImplTest
package com.progressive.code.resource.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Created by abraun on 14/11/2017.
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CountryServiceImplTest {
@Autowired
private CountryService countryService;
@Test
public void testGetCountryByIsoCode() {
String countryName = countryService.getCountryByIsoCode("CA");
assertEquals("Canada", countryName);
}
@Test
public void testGetAllCountries() {
Map countries = countryService.getAllCountries();
assertNotNull(countries);
assertEquals(4, countries.size());
assertEquals("Canada", countries.get("CA"));
assertEquals("Germany", countries.get("DE"));
}
}
Get the Code on GitHhub
The code for this post is available in this GitHub repository.
Tags
AOP Apache Kafka Bootstrap Go Java Linux MongoDB Nginx Security Spring Spring Boot Spring Security SSL ThymeleafSearch
Archive
- 1 December 2023
- 1 November 2023
- 1 May 2019
- 2 April 2019
- 1 May 2018
- 1 April 2018
- 1 March 2018
- 2 February 2018
- 1 January 2018
- 5 December 2017
- 7 November 2017
- 2 October 2017