How to get all resources inside a resource directory in a JAR file?
Asked Answered
S

3

5

I'm using Spring Boot and I want to get resources.

Here's my directory structure:

├───java
│   └───...
├───resources
│   └───files
│       ├───file1.txt
│       ├───file2.txt
│       ├───file3.txt
│       └───file4.txt

I'm trying to get the resources in the files directory. Here's what I've done to access these files:

@Autowired
private ResourceLoader resourceLoader;

...
Stream<Path> walk = Files.walk(Paths.get(resourceLoader.getResource("classpath:files/").getURI()));

This works running locally when the files are in the target directory, but the files are not found when I run it from a JAR file. How do I fix this? I've checked that these files do exist in the jar located under BOOT-INF/classes/files.

Here's how maven is building and copying the resources into the JAR (I don't want the .txt files to be filtered):

<resources>
  <resource>
    <directory>src/main/resources</directory>
    <filtering>true</filtering>
    <excludes>
      <exclude>**/*.txt</exclude>
    </excludes>
  </resource>
  <resource>
    <directory>src/main/resources</directory>
    <filtering>false</filtering>
    <includes>
      <include>**/*.txt</include>
    </includes>
  </resource>
</resources>
Suds answered 22/7, 2019 at 16:19 Comment(12)
It can't find the file.Suds
Are they packaged in the jar ?Nollie
Are you using gradle or maven in this project ?Yonah
Yes, they are. It's in the BOOT-INF/classes/files directory.Suds
@Yonah it's a maven projectSuds
@George, if I understand your question, when you create a jar file, you do not these *.txt files. Post your pom.xml file for more details.Yonah
In general there is not point of generating file system dependent path for file inside zip as they are useless when using filesystem api.Morie
@Yonah I've added pom file snippet.Suds
@Morie It's a directory? How do I get a directory if it's not a path?Suds
@ArnaudClaudel I get a FileNotFoundException when I call getResource("files/")Suds
I deleted my comment just after, I was wrong ^^Nollie
It does not matter. Resources are INSIDE JAR. You dont have access to that using file system API - but you can get input stream directly.Morie
Y
8

Can you try with the following code to read the files ?

ResourcePatternResolver resourcePatResolver = new PathMatchingResourcePatternResolver();
Resource[] AllResources = resourcePatResolver.getResources("classpath*:files/*.txt");
 for(Resource resource: AllResources) {
    InputStream inputStream = resource.getInputStream();
    //Process the logic
 }

This is not the exact solution for the code you have written, but it will give an outline about the resources to read.

Yonah answered 22/7, 2019 at 16:56 Comment(0)
V
0

Someone else had the same issue as you and they found the solution by combining the ResourceLoader with the ResourcePatternResolver as Sambit suggested. See here for the same issue with answer: https://mcmap.net/q/2032689/-reading-files-in-a-springboot-2-0-1-release-app

Valenta answered 22/7, 2019 at 19:19 Comment(0)
R
0

The below example code does read/load the Drools files configured as part of rules/ folder located under /src/main/resources project path in case of local Windows based development environment i.e. as part of IDE while from application jar in case of Linux/Unix based production environment.

Incorporated the approach to read/load the files using the java.lang.ClassLoader.getResource(String name) method in case of local Windows development environment while used the org.springframework.core.io.support.ResourcePatternUtils.getResourcePatternResolver(ResourceLoader resourceLoader) returned org.springframework.core.io.support.ResourcePatternResolver.getResources(String locationPattern) method to read/load the files from application jar when deployed in Linux based production environment.

NOTE: The above said example will not work if you use the command line to execute the application jar in Windows environment using the below command:

java -jar questionaries-rules-0.0.1-SNAPSHOT.jar

In this case you need to make a call to loadResourcesOfRulesFromJar() method to make it work in Windows or Linux/Unix environment.

You can add the logic to switch between the local development environment and prod environment as per your requirement either by considering OS type along with some configuration mechanism to meet the development and deployment needs.

Drools Configuration

/**
 * @author dinesh.lomte
 */
package com.dl.questioneries.rules.api.config;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternUtils;

import com.dl.questioneries.rules.api.exception.SystemException;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
public class DroolsConfiguration {

    private final KieServices kieServices = KieServices.Factory.get();
    private ResourceLoader resourceLoader;

    /**
     * 
     * @param resourceLoader
     */
    @Autowired
    public DroolsConfiguration(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
    
    /**
     * 
     * @return
     * @throws SystemException
     */
    @Bean
    public KieContainer kieContainer() throws SystemException {

        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();

        File[] files = 
                System.getProperty("os.name").contains("Windows")
                ? loadResourcesOfRulesFromLocalSystem()
                : loadResourcesOfRulesFromJar();
        if (files == null || files.length == 0) {
            String message = "Failed to load the '.drl' files located under resources specific rules folder.";
            log.error(message);
            throw new SystemException(
                    "SYS_ERROR_00001", message, new Exception(message));
        }
        for (File file : files) {
            kieFileSystem.write(ResourceFactory.newFileResource(file));
        }
        log.info("Loaded the configured rule files successfully.");
        KieBuilder Kiebuilder = kieServices.newKieBuilder(kieFileSystem);
        Kiebuilder.buildAll();

        return kieServices.newKieContainer(
                kieServices.getRepository().getDefaultReleaseId());
    }
    
    /**
     * 
     * @return
     */
    private File[] loadResourcesOfRulesFromJar() {
        
        log.info("Loading the configured rule files from Jar.");
        Resource[] resources = null;
        List<File> files = new ArrayList<>();
        try {
            resources = ResourcePatternUtils
                    .getResourcePatternResolver(resourceLoader)
                    .getResources("classpath*:rules/*.drl");
            InputStream inputStream = null;
            File file = null;
            for (Resource resource : resources) {
                try {
                    inputStream = resource.getInputStream();
                    file = File.createTempFile(
                            resource.getFilename().substring(
                                    0, resource.getFilename().length() - 4), 
                            ".drl");
                    FileUtils.copyInputStreamToFile(inputStream, file);
                } finally {
                    inputStream.close();
                }
                log.info("'{}'", resource.getFilename());
                files.add(file);
            }
        } catch (IOException ioException) {
            String message = new StringBuilder(
                    "Failed to load the '.drl' files located under resources specific rules folder.")
                    .append(ioException.getMessage()).toString();
            log.error(message, ioException);
            throw new SystemException(
                    "SYS_ERROR_00001", message, ioException);
        }
        return (File[]) files.toArray(new File[files.size()]);
    }
    
    /**
     * 
     * @return
     */
    private File[] loadResourcesOfRulesFromLocalSystem() {
        
        log.info("Loading the configured rule files from local system.");
        try {
            File files = new File(
                    getClass().getClassLoader().getResource("rules/").getPath());
            return files.listFiles();
        } catch (Exception exception) {
            String message = new StringBuilder(
                    "Failed to load the '.drl' files located under resources specific rules folder.")
                    .append(exception.getMessage()).toString();
            log.error(message, exception);
            throw new SystemException(
                    "SYS_ERROR_00001", message, exception);
        }
    }
}

Rest Controller

/**
 * @author dinesh.lomte
 */
package com.dl.questioneries.rules.api.controller;

import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.dl.questioneries.rules.api.model.Question;

@RestController
public class QuestioneriesRulesController {

    @Autowired
    private KieContainer kieContainer;

    /**
     * 
     * @param question
     * @return
     */
    @PostMapping(path = "/getQuestion", 
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public Question fetchQuestion(@RequestBody Question question) {
        
        KieSession kieSession = kieContainer.newKieSession();
        kieSession.insert(question);
        kieSession.fireAllRules(1);
        
        return question;
    }
}
Rondelle answered 25/9, 2023 at 2:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.