Spring boot: load text file lines at Bean creation time

Elvis Ciotti
2 min readOct 12, 2021

To access a resource file from Spring, you can’t just refer to it to its path(“src/main/resources/words.txt”) as when packaged into the JAR, the path will likely change (depending on your config).

The simplest thing to do is placing the file inside the resource directory, and refer to it as “classpath:words.txt”

Caveat: you cannot transform the Spring resource into a java.io.File; it’d fail when packaged as the file structure does not exist in the JAR file. In the example below I access the file by getting the input stream from the resource, then constructing a InputStreamReader wrapped by a BufferedReader that allows to get the stream of lines.

“class path resource cannot be resolved to absolute file path because it does not reside in the file system” ← that’s what you might get otherwise

Working example

Below an example of Bean/Service loading words.txt (placed into src/main/resources/words.txt) (tested in Spring boot 2.4), that — at construction time — reads all the non-empty into a Set, logs the operation and customises the error in case of IOException (file not accessible or not readable). Note that I’m deliberately throwing the exception in order to stop Spring to start as I don’t want the app to start and misbehave without clearly telling me.

package com.boardintelligence.writerapi.service.recommendations;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j //Lombok
public class SectionMetricsService {
Set<String> words;

@Autowired
public SectionMetricsService(
@Value("classpath:words.txt") Resource resourceFile
) {
words = loadWords(resourceFile);
}

private Set<String> loadWords(Resource resource) {
try {
InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
Set<String> wordsInFile = new BufferedReader(inputStreamReader)
.lines()
.filter(line -> !StringUtils.isEmpty(line))
.map(s -> s.trim().toLowerCase())
.collect(Collectors.toSet());
log.info(
"Loaded {] with {} words",
resource.getFilename(),
wordsInFile.size()
);
return wordsInFile;
} catch (Exception e) {
throw new RuntimeException(
"Error reading %s: %s".formatted(resource.getFilename(), e.getMessage()),
e
);
}
}
}

Clap if saved some of your time.

Comment for corrections.

--

--

Elvis Ciotti

Software Contractor — Java, Spring, k8s, AWS, Javascript @ London - hire me at https://www.linkedin.com/in/elvisciotti