0

(I am new to java, please be understanding)

I am writting a application in java that needs a config file, the config file is a json file, I neeed to open it and read it's contents but no matter how I try I cannot do it, I have done hours of looking on the internet but I cannot find a working way

I have tried using my POM.xml to create a resource folder, and then using .getResource() but that doesn't seem to work

My java

public class MusicOrganizer {

    public static String configURL = "assets/config.json";
    public static String configSource;

    public static void main(String[] args) {

        try {

            configSource = MO.getFileFromResources(configURL);

        } catch (IOException e) {

            // This isn't what is going wrong

            System.out.println("Error reading config file!\n" + e + "\nDisplaying error screen...");

            errorScreen.main("Error Reading Config", "Try redownloading the application.","ERC_001");

            return;

        }

    }

    private String getFileFromResources(String fileName) throws IOException {

        ClassLoader classLoader = getClass().getClassLoader();

        URL resource = classLoader.getResource(fileName);
        if (resource == null) {
            throw new IllegalArgumentException("file is not found!"); // this is what is going wrong
        } else {
            return printFile(new File(resource.getFile()));
        }

    }

    private static String printFile(File file) throws IOException {

        if (file == null) throw new IllegalArgumentException("file is not found!");

        String source = "";

        try (FileReader reader = new FileReader(file);
             BufferedReader br = new BufferedReader(reader)) {

            String line;
            while ((line = br.readLine()) != null) {
                source += line;
            }

            return source;
        }
    }

}

My POM.xml where I create my "resource folder"

<build>
     <resources>
        <resource>
            <directory>assets</directory>
        </resource>
     </resources>
</build>

Please tell me what I am doing wrong, I want to have my java file (while in compressed .jar form) read what is in the "config.json" file.

I am using NetBeans 11.1, java version "12.0.2" 2019-07-16, Java(TM) SE Runtime Environment (build 12.0.2+10), Java HotSpot(TM) 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing), and a MacBook Pro

My directory paths:


>ROOT
  >nb-configuration.xml
  >nbactions.xml
  >pom.xml
  >src
    >main
      >java
        >com
          >[my name]
            >musicorganizer
              [java files]
        >JSON
          [java files]
      >resources
        config.json
    >test
      >java
        [nothing here]
  >target
    [Stuff]

Phayden
  • 21
  • 1
  • 6
  • You would need to use getResourceAsStream() if it is in a JAR: https://stackoverflow.com/questions/20504014/accessing-resources-inside-a-jar?noredirect=1&lq=1 and https://stackoverflow.com/questions/3861989/preferred-way-of-loading-resources-in-java – KellyM Aug 17 '19 at 21:30
  • 3
    Resources cannot be read via the usual file APIs (e.g. `File`). To read the contents of a resource you need to open an `InputStream` to it, either through the `URL` returned by `#getResource(String)` or directly via `#getResourceAsStream(String)`. Also, it should not be necessary to add a resources root—just use the standard, default directory (i.e. `src/main/resources`). As for not finding the resource, what does your directory structure look like? – Slaw Aug 17 '19 at 21:36
  • I added my directory structure – Phayden Aug 17 '19 at 21:58
  • 3
    You first need to be clear on what you want. Do you want a read-only, uneditable resource embedded ito the jar file produced by your build, or do you want an external, editable, configuration file that the user or the program can edit to change the configuration? If the former, use a resource located inder src/main/resources, and read it using `MyClass.class.getResourceAsStream("/thefile.json")`. Otherwise, dont make it a resource. Make it a file located under the user home directory for example, and use file IO to read/write it. – JB Nizet Aug 17 '19 at 22:06
  • The latter, I want to be able to edit it, via java, I used to be able to do it via `File` but when it got compressed into a .jar that didn't work anymore. sorry if I am not being clear enough – Phayden Aug 17 '19 at 22:11
  • Additionally, remove your POM configuration (use the defaults until you understand this well) and put your file at `src/main/resources/assets/config.json` (it will be available with `getResourceAsStream("assets/config.json")`). – chrylis -cautiouslyoptimistic- Aug 17 '19 at 22:11
  • 2
    Then it should ne be a resource. It should be a plain old file on the file system. Don't try to use Maven to embed it into the jar, since you precisely don't want that. – JB Nizet Aug 17 '19 at 22:12
  • Ah, you should presume that resources are immutable (read out of the jar) and use an external file or other storage if you want to edit it. – chrylis -cautiouslyoptimistic- Aug 17 '19 at 22:12
  • I used the default resource path `src/main/resources/assets/config.json`, and i used `getResourceAsStream("assets/config.json")` to get it, and it returns null – Phayden Aug 17 '19 at 22:17

1 Answers1

0

In general, unless you have good reason to, you probably don't need to overwrite maven's default configuration.

Maven uses a "convention over configuration" philosophy, meaning it:

  • assumes sensible default values for properties
  • allows you to overwrite this if you need to

So, if you want a resource folder, maven provides one for you by default (assuming you follow the default project structure)

You should have a resource folder at src/main/resources, with your Java code in src/main/java/<package-name>. This is the default structure that maven expects.

From there you can get a reference to this by using Class.getResource(). For example, if you have a file in src/main/resources/file.txt, you can access it with getClass().getResource("/file.txt") (note the leading slash).

However, if you want to modify this during runtime (perhaps if a user wants to save new details), you should not use resources. Instead, consider one of the following:

  • File in current directory - just use new File("config.txt") and read/write to that
  • File in user home directory - use new File(System.getProperty(user.home), "config.txt"). On Windows for example this creates a file at C:/users/<username>/config.txt.
  • Database - If your application already uses a database, it can be a good place to store a lot of configuration options, although, based on your question, I imagine this is not suitable for you.
cameron1024
  • 9,083
  • 2
  • 16
  • 36
  • `getClass().getResource("/config.json")` returns a url, and not the file content, how would I get the file content from that? – Phayden Aug 17 '19 at 23:18
  • if I do that, I get `no suitable constructor found for File(URL)` – Phayden Aug 17 '19 at 23:22
  • My mistake, you need to call `new File(getClass().getResource("/config.txt").getFile())` – cameron1024 Aug 17 '19 at 23:24
  • 2
    @cameron1024 **Never** call the `getFile()` method of URL. It does not return a valid file name! It just returns the path portion of a URL, which may have percent-escapes for the many characters which are not allowed to appear directly in a URL. Furthermore, if the URL wasn’t a `file:` URL, the path won’t be usable as a file name anyway. The only correct way to read a URL is by opening it, such as with its `openStream` method. – VGR Aug 18 '19 at 03:37
  • Understood - out of curiousity, do you know what the intended purpose of 'getFile()` is? – cameron1024 Aug 18 '19 at 11:07