13

My project structure looks like below. I do not want to include the config file as a resource, but instead read it at runtime so that we can simply change settings without having to recompile and deploy. my problem are two things

  1. reading the file just isn't working despite various ways i have tried (see current implementation below i am trying)
  2. When using gradle, do i needto tell it how to build/or deploy the file and where? I think that may be part of the problem..that the config file is not getting deployed when doing a gradle build or trying to debug in Eclipse.

My project structure:

myproj\
        \src
            \main
                \config
                    \com\my_app1\
                                config.dev.properties
                                config.qa.properties
                \java
                    \com\myapp1\
                                \model\
                                \service\
                                \util\
                                    Config.java
            \test              

Config.java:

public Config(){
        try {
            String configPath = "/config.dev.properties"; //TODO: pass env in as parameter
            System.out.println(configPath);
            final File configFile = new File(configPath);
            FileInputStream input = new FileInputStream(configFile);

            Properties prop = new Properties()
            prop.load(input);
            String prop1 = prop.getProperty("PROP1");
            System.out.println(prop1);
        } catch (IOException ex) {
            ex.printStackTrace();
        } 
    }   
mike01010
  • 5,226
  • 6
  • 44
  • 77
  • I don't know how and where do you deploy application, but can you just use it:https://github.com/stevesaliman/gradle-properties-plugin ? Second option is to have one static path to file which will contain paths to other configs. – Michał Piątkowski Feb 21 '17 at 17:34
  • Could you share your actual build.gradle ? – ToYonos Feb 24 '17 at 11:01

5 Answers5

5

Ans 1.

reading the file just isn't working despite various ways i have tried (see current implementation below i am trying)

With the location of your config file you have depicted,

Change

String configPath = "/config.dev.properties";

to

String configPath = "src\main\config\com\my_app1\config.dev.properties";

However read the second answer first.

Ans 2:

When using gradle, do i needto tell it how to build/or deploy the file and where? I think that may be part of the problem..that the config file is not getting deployed when doing a gradle build or trying to debug in Eclipse.

You have two choices:

  1. Rename your config directory to resources. Gradle automatically builds the resources under "src/main/resources" directory.
  2. Let Gradle know the additional directory to be considered as resources.

    sourceSets {
        main {
            resources {
                srcDirs = ["src\main\config\com\my_app1"]
                includes = ["**/*.properties"]
            }
        }
     }
    
VHS
  • 9,534
  • 3
  • 19
  • 43
  • 2
    I think the poster doesn't want the file packed inside a jar and wants it in a directory where it can be tweaked without unzipping & zipping again – lance-java Feb 22 '17 at 14:09
  • I would tweak my answer if OP confirms that's what he needs. – VHS Feb 22 '17 at 15:31
  • @VHS - your answer is closest to what i a want, in particular, Ans 2.2. Yes lance, i want it externally. So i specified the entry in build.gradle as you indicated, and i see now that when i do a gradle build, it creates a /my_app1/build/resources/main folder. I am still not able to read this with the code i have above however. the error is: "java.io.FileNotFoundException: \config.dev.properties (The system cannot find the path specified)" – mike01010 Feb 22 '17 at 16:16
  • @VHS, I am debugging this through eclipse after building it. Wondering if i have to let eclipse know where the resource files are for a given project? – mike01010 Feb 22 '17 at 16:33
  • @mike01010, if you are debugging it through `Eclipse`, the relative paths are all relative to the project folder - the folder which has the`src` folder. So if your `build` folder is at the same level as `src`, you can use `build/resources/main/config.dev.properties`. – VHS Feb 22 '17 at 16:43
  • @VHS, that works, but i don't think that code is deployable, since there won't be a 'build' folder when deployed. would be nice if the relative path works for both debugging in eclipse as well as runtime – mike01010 Feb 22 '17 at 19:12
  • @mike01010, I understand your concern. That's why people recommend reading files from classpath instead of from a relative path. If a resource file is on classpath, you don't need to specify any path regardless of whether the run time is within eclipse or outside. – VHS Feb 22 '17 at 19:29
  • @VHS can you point me how to do that. i actually did try renaming the config folder to 'resources' and using ClassLoader.class.getResourceAsStream, to no avail. Also, does this method allow us to change config entries without having to re-build and re-deploy? – mike01010 Feb 22 '17 at 19:38
  • See if [this](http://stackoverflow.com/questions/1464291/how-to-really-read-text-file-from-classpath-in-java) helps. – VHS Feb 22 '17 at 19:53
  • @VHS thanks, seems like that will compile the config into the jar. not an option for us. We'd like to change values in the config at run-time. will try to figure out best way to do this – mike01010 Feb 22 '17 at 22:10
4

reading the file just isn't working despite various ways i have tried (see current implementation below i am trying)

You need to clarify this statement. Are you trying to load properties from an existing file? Because the code you posted that load the Properties object is correct. So probably the error is in the file path.

Anyway, I'm just guessing what you are trying to do. You need to clarify your question. Is your application an executable jar like the example below? Are trying to load an external file that is outside the jar (In this case gradle can't help you)?

If you build a simple application like this as an executable jar

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class Main {
    public static void main(String[]args) {
        File configFile = new File("test.properties");
        System.out.println("Reading config from = " + configFile.getAbsolutePath());

        FileInputStream fis = null;
        Properties properties = new Properties();

        try {
            fis = new FileInputStream(configFile);
            properties.load(fis);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } finally {
            if(fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {}
            }
        }

        System.out.println("user = " + properties.getProperty("user"));
    }
}

When you run the jar, the application will try to load properties from a file called test.properties that is located in the application working directory.

So if you have test.properties that looks like this

user=Flood2d

The output will be

Reading config from = C:\test.properties
user = Flood2d

And that's because the jar file and test.properties file is located in C:\ and I'm running it from there.

Some java applications load configuration from locations like %appdata% on Windows or /Library/Application on MacOS. This solution is used when an application has a configuration that can change (it can be changed by manually editing the file or by the application itself) so there's no need to recompile the application with the new configs.

Let me know if I have misunderstood something, so we can figure out what you are trying to ask us.

Flood2d
  • 1,338
  • 8
  • 9
1

Your question is slightly vague but I get the feeling that you want the config files(s) to live "outside" of the jars.

I suggest you take a look at the application plugin. This will create a zip of your application and will also generate a start script to start it. I think you'll need to:

  1. Customise the distZip task to add an extra folder for the config files
  2. Customise the startScripts task to add the extra folder to the classpath of the start script
lance-java
  • 25,497
  • 4
  • 59
  • 101
1

The solution for me to be able to read an external (non-resource) file was to create my config folder at the root of the application.

myproj/
      /configs

Doing this allowed me to read the configs by using 'config/config.dev.properies'

mike01010
  • 5,226
  • 6
  • 44
  • 77
1

I am not familiar with gradle,so I can only give some advices about your question 1.I think you can give a full path of you property file as a parameter of FileInputStream,then load it using prop.load.

FileInputStream input = new FileInputStream("src/main/.../config.dev.properties");

Properties prop = new Properties()
prop.load(input);
// ....your code
fanshaoer
  • 99
  • 2
  • 11
  • Please do not post code only answers, instead explain what your code does and how it solves OPs problems. – LJᛃ Feb 28 '17 at 04:08