Search code examples
javainputstream

How to specify the path for getResourceAsStream() method in java


I know this question has been asked several times but I still can't get it work by those solutions.

I have a maven project. And one Config.java file located in consumer/src/main/java. Here's the content:

import java.util.Properties;

public class Config {
    Properties configFile;
    public Config() {
        configFile = new Properties();
        try {
            configFile.load(this.getClass().getClassLoader().
                    getResourceAsStream("property_table.config.txt"));
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public String getProperty(String key) {
        String value = this.configFile.getProperty(key);
        return value;
    }
    public static void main(String[] args) {
        Config config = new Config();
        System.out.println("URL: " + config.getProperty("URL"));
        System.out.println("PASSWORD: " + config.getProperty("PASSWORD"));
    }
}

I kept getting nullpointer exception. I know that's because it can't find the file property_table.config.txt.

At first I put the property_table_config.txt file in the same folder(consumer/src/main/java/) as Config.java file. And tried use /property_table_config.txt and 'property_table_config.txt`. Neither of them work.

And then I tried using absolute path, not working. And tried using /main/java/property_table_config, not working either.

Then I saw this solution: https://stackoverflow.com/a/2103625/8159477. So I make a directory called resources and put it under main folder (i.e. the path of the folder is consumer/src/main/resources, and create a sub-folder config under resources. After putting the property_table_config.txt file there, I changed the code into this:

configFile.load(this.getClass().getClassLoader().getResourceAsStream("/config/property_table.config.txt"));

But this still didn't work. Can anyone give some hint on this? Any suggestions will be appreciated!!


Solution

  • According to Class.getResourceAsStream:

    This method delegates to this object's class loader. If this object was loaded by the bootstrap class loader, the method delegates to ClassLoader.getSystemResourceAsStream.

    Before delegation, an absolute resource name is constructed from the given resource name using this algorithm:

    • If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
    • Otherwise, the absolute name is of the following form:
      modified_package_name/name
      Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').

    This is how I understand the comments:

    • If you use ClassLoader.getResourceAsStream, send the absolute path from package root, but omitting the first /.
    • If you use Class.getResourceAsStream, send either a path relative the the current Class object (and the method will take the package into account), or send the absolute path from package root, starting with a /.

    But in addition to this, you need to be cognizant of your build system. With maven, resource files are stored under src/main/resources.

    So, in your case, I believe making the following changes should resolve the issue:

    • Put the file in src/main/resources.

    • Change the code to

       this.getClass()
            .getResourceAsStream("/property_table.config.txt")
            //or `Config.class.getResource...
      
    • Alternatively, use

        this.getClass().getClassLoader()
                        .getResourceAsStream("property_table.config.txt")`
      

    I've tried this with a similar setup, and it works as expected.