0

I am creating a Jar file to store common code for some of my other applications. Within one of the classes, I want to essentially load a csv file into an object, and allow applications that use the jar to access this object. I am using Java 8 and Apache Commons-csv.

Here is what I currently have:

public class MyServices {

    public static final String CSV_SRC = "src/main/resources/MyCSV.csv";

    private final List<MyCSVObj> allObjectsFromCSV;

    public MyServices() {
        this.allObjectsFromCSV = importMyCSV();
    }

    private List<MyCSVObj> importMyCSV() {
        try {
            Reader in = new FileReader(CSV_SRC);
            Iterable<CSVRecord> records = CSVFormat.EXCEL.withHeader().parse(in);
            List<MyCSVObj> ret = new ArrayList<>();
            for (CSVRecord record : records) {
                ... // Get all fields
                // Add fields to list
            }
            return ret;
        } catch (Exception e) {
            LOGGER.error("Could not load csv", e);
        }

        return new ArrayList<>();
    }

    ...
}

This works within eclipse and passes all tests. However, after compiling this as a jar and trying to use it within other projects, I get the specified exception "could not load csv" based on FileNotFoundException.

I have looked for the subject and a number of people have said to get the resource as a stream. Unfortunately, googling "Java import csv as stream", but this gives a bunch of manual csv parsing with Java 8 streams rather than using a CSV library.

I have also tried this with the same results (passes all tests in eclipse, but file does not load when imported to other projects):

FileInputStream is = new FileInputStream(CSV_SRC);
Reader in = new InputStreamReader(is);
Iterable<CSVRecord> records = CSVFormat.EXCEL.withHeader().parse(in);

and this

Reader in = new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("MyCSV.csv"));
Iterable<CSVRecord> records = CSVFormat.EXCEL.withHeader().parse(in);

Any suggestions on how to resolve the FileNotFoundException?

Kyle Grage
  • 715
  • 1
  • 9
  • 15
  • 2
    Well, you are trying to open a file `src/main/resources/MyCSV.csv` relative to the current directory. If there is no such file, you get a `FileNotFoundException`. It’s really that simple. And you will surely find a lot of articles and tutorials about how to use resources, if you stop considering your issue to be CSV specific. – Holger Feb 14 '18 at 16:05
  • try this `Reader in = new FileReader(new ClassPathResource("MyCSV.csv").getFile())` – pvpkiran Feb 14 '18 at 16:07
  • 1
    @pvpkiran when you pack your resources in a Jar file, there is no `File`, but jar entries. Any attempt to access the resource as `File` will fail. – Holger Feb 14 '18 at 16:09
  • if you want to use it in other projects doesn't it makes sense to take file location or File object as an argument to your function? – pvpkiran Feb 14 '18 at 16:14
  • 1
    @pvpkiran it doesn’t matter what you want, jar entries are not files in the local filesystem, therefore, it is *impossible* to convert them to a `File`. If you want to share a file between different applications, you must not use an embedded resource. Of course, it is possible to refer to a file within your Eclipse workspace, like the OP does when running the software within Eclipse, however, you have to face the fact that this file only exist when the Eclipse environment is available. – Holger Feb 14 '18 at 16:19
  • You can use something like `String path = new File(".").getCanonicalPath();` to get your current path and then concatenate with your `CSV_SRC` variable – Hackerman Feb 14 '18 at 16:25
  • @Holger I agree. I believe OP wants to ship this program which converts a CSV into list of objects as a utility jar, which anyone can use in their application. Anyway it is not clear. – pvpkiran Feb 14 '18 at 16:26
  • Yes, I want to import the CSV as a list of defined objects, and I want other projects to be able to access that list – Kyle Grage Feb 14 '18 at 17:34
  • So to be clear, I want other projects to import this jar, and do something like `List obj = new MyServices().getAllObjectsFromCSV();` I know I can technically hack around this and hard code something like `this.allObjectsFromCSV = new ArrayList() {{ add(new MyCSVObj(...)); ...//thousands of MyCSVObj's }};` but I would like to avoid doing that if at all possible – Kyle Grage Feb 14 '18 at 17:45
  • Using `getResourceAsStream` is going into the right direction, now, the question is how you have set up your project, i.e. where in the output folder is your resource copied to. E.g. if `src` is you source folder, you would have to use `getClass().getResourceAsStream("/main/resources/MyCSV.csv")`, but if your source folder is `src/main`, it would be `getClass().getResourceAsStream("/resources/MyCSV.csv")`. – Holger Feb 15 '18 at 08:20
  • @Holger My project is set up using gradle. By default, it builds `src/main/java`, `src/main/resources`, `src/test/java`, and `src/test/resources`. I think gradle compiles the `src/main` into the jar, so I should consider that my resource folder, but am not positive. If anything, I can always give both a try too, I'll see how it works – Kyle Grage Feb 20 '18 at 15:46
  • So I have tried all of `/resources/MyCSV.csv`, `/main/resources/MyCSV.csv` and `/src/main/resources/MyCSV.csv`. The build fails because of failing tests (from not being able to locate the file). Using `MyCSV.csv` is the only one that seems to work in terms of loading for the tests. – Kyle Grage Feb 20 '18 at 16:05
  • As I tried to explain in my previous comment, the relevant path is the path from «whatever root your build process uses» to the resource. So if it uses `src/main/resources`, the resulting path to your resource would be `MyCSV.csv` and when resolving it relative to a `Class`, it would be `/MyCSV.csv`, so `getClass().getResourceAsStream("/MyCSV.csv")` would be the way to go. This should also be identical to the path within the `jar` file, so when you list the `jar` file’s contents, `MyCSV.csv` should appear with no prefix there. – Holger Feb 20 '18 at 16:21
  • using `/MyCSV.csv` appears to also cause the tests to fail – Kyle Grage Feb 20 '18 at 16:44

0 Answers0