lsiva
lsiva

Reputation: 485

Reading file inside Spring boot fat jar

We have a spring boot application which has a legacy jar api that we use that needs to load properties by using InputFileStream. We wrapped the legacy jar in our spring boot fat jar and the properties files are under BOOT-INF/classes folder. I could see spring loading all the relevant properties but when I pass the properties file name to the legacy jar it could not read the properties file as its inside the jar and is not under physical path. In this scenario how do we pass the properties file to the legacy jar?

Please note we cannot change the legacy jar.

Upvotes: 4

Views: 6771

Answers (4)

M. Khodadadi
M. Khodadadi

Reputation: 31

According to @moldovean's solution, you just need to call 'getResourceAsStream(path)' and continue with returned InputStream. Be aware that the 'path' is based on ClassPath. For example:

InputStream stream = this.getClass().getResourceAsStream("/your-file.csv");

In root of your class path, there is a file named 'your-file.csv' that you want to read.

Upvotes: 0

moldovean
moldovean

Reputation: 3261

I also have faced this issue recently. I have a file I put in the resource file, let's call it path and I was not able to read it. @madoke has given one of the solutions using FileSystem. This is another one, here we are assuming we are in a container, and if not, we use the Java 8 features.

@Component 
@Log4j2
public class DataInitializer implements 
    ApplicationListener<ApplicationReadyEvent> {

private YourRepo yourRepo; // this is your DataSource Repo

@Value(“${path.to.file}”). // the path to file MUST start with a forward slash: /iaka/myfile.csv
private String path;

public DataInitializer(YourRepo yourRepo) {
    this.yourRepo = yourRepo;
}

@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
    try {
        persistInputData();
        log.info("Completed loading data");
    } catch (IOException e) {
        log.error("Error in reading / parsing CSV", e);
    }
}

private void persistInputData() throws IOException {
    log.info("The path to Customers: "+ path);
    Stream<String> lines;
    InputStream inputStream = DataInitializer.class.getClassLoader().getResourceAsStream(path);
    if (inputStream != null) { // this means you are inside a fat-jar / container
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        lines = bufferedReader.lines();
    } else {
        URL resource = this.getClass().getResource(path);
        String path = resource.getPath();
        lines = Files.lines(Paths.get(path));
    }

    List<SnapCsvInput> inputs = lines.map(s -> s.split(","))
                                     .skip(1) //the column names
                                     .map(SnapCsvInput::new)
                                     .collect(Collectors.toList());
    inputs.forEach(i->log.info(i.toString()));
    yourRepo.saveAll(inputs);

}

}

Upvotes: 2

madoke
madoke

Reputation: 873

Actually you can, using FileSystem. You just have to emulate a filesystem on the folder you need to get the file from. For example if you wanted to get file.properties, which is under src/main/resources you could do something like this:

FileSystem fs = FileSystems.newFileSystem(this.getClass().getResource("").toURI(), Collections.emptyMap());
String pathToMyFile = fs.getPath("file.properties").toString();
yourLegacyClassThatNeedsAndAbsoluteFilePath.execute(pathToMyFile)

Upvotes: 2

GreyBeardedGeek
GreyBeardedGeek

Reputation: 30088

Basically, you can't, because the properties "file" is not a file, it's a resource in a jar file, which is compressed (it's actually a .zip file).

AFAIK, the only way to make this work is to extract the file from the jar, and put it on your server in a well-known location. Then at runtime open that file with an FileInputStream and pass it to the legacy method.

Upvotes: 0

Related Questions