views:

537

answers:

5

I have several classes that need to load some properties files, and I was wondering what are the best practices to accomplish this. I thought of two basic approaches:

  • Hardcode the properties file name in each class, and then use the Properties class to load from a FileInputStream, which can be problematic if someone decides to change the name of the properties file, as it is hardcoded in the code.

    public class A {
        public A() {
            Properties p = new Properties().load(
                    new FileInputStream("properties/Aconfig.properties"));
            String value = p.getProperty("key", "");
        }        
    }
    
  • Create a method that, given a class name, loads a properties file that has the same name as the class. Though this approach doesn't require to hardcode the properties file name, it does require that we follow some convention in naming the files, which can cause confusion.

    public class A {
        public A() {
            Properties p = PropertiesHelper.loadFromClassName(A.class.getName());
            // here, we **assume** that there is a A.properties file in the classpath.
        }
    }
    

However, there may be many other more elegant approaches, and that's why I posed these questions: i) What are the best practices for loading properties files in Java?; ii) Do you use any helper class that takes care of the job?; iii) Where (in the code) do you typically load the properties file?

Also, is it OK for a class to "auto-load" its properties? Or should I pass the arguments that I need to the constructor ? The problem of passing the arguments, is that there are way too many for some classes (~20, which represent parameters in a statistical model).

A: 

In the past, I have loaded properties through a system property - the file name is passed in through the system property, and I load up that file. There is a default name that we use if the system property is not set. If the file does not exist, then you need to decide what to do there.

The nice thing about this is there is a standard, but they can override it's location/name using a command line argument.

Just my 2 cents though.

aperkins
+1  A: 

Have several places for a properties files and load them (one after another) into a single Properties object. This scheme allow a mapping to have a default value that can then be overridden at several points.

Itay
+1  A: 

The file names can easily be passed in the command line for the app. This can be done either as an arg to the main method (after the main class name) or as a property (as aperkins is alluding, i believe) using the -D flag.

akf
I'm aware of that, but I need my application to work in a web environment as well. Also, I have many many file names to be passed, and I'd need to change my run.sh (or similar) script everytime I created a new one, using that method.
JG
If you hard coded your filenames, you be in a similar position. You could have a filename on the commandline that contains a list of config files that you need.
akf
+2  A: 

The best practice would be to use some kind of dependency injection container - for example Spring Framework or Google Guice.

It solves all kinds of problems - you don't tie your class to particular property file name, you don't have to worry about loading said properties within that class and handle possible exceptions, and you don't have to pass 30 property file names as command line arguments (or system properties).

It also helps with many, many other things in addition to property loading :-) - try it, and you'll wonder how you ever lived without.

Update: Incidentally, your other question is also one of those things that Spring would take care of.

Update #2: I just realized I've already tried to push Spring on you :-) At the risk of repeating myself, Spring would really help with abstraction here. Depending on what you store in your property files you may not need them at all (if they deal with configuration) or you will get a very nice API for dealing with them (if they're resource bundles or something similar) .

ChssPly76
Yes : ), I'm considering to use SF for that particular problem. However, for this, I want the properties files to be easily configured/changed by everyone (not necessarily a computer programmer), hence the need for a simple "key=value"-based file schema.
JG
You can still very much do that. Spring has a very nice resource abstraction layer: http://static.springsource.org/spring/docs/2.5.x/reference/resources.html that would let you deal with those property files "as is" without tying your classes to them directly.
ChssPly76
Hmm, I'm going to read about that, thanks. I thought you were referring to the <property> element inside <bean>. As for your question, I basically store many model parameters in it (e.g., numberOfTrials=50, et cetera [numerical values]).
JG
`<property>` element is where you'd put your properties file name; then inside your class you'll have a corresponding setter taking Resource as parameter. As far as model parameters go, those may or may not be good candidates for setting via `<property>` - that depends on whether they have reasonable "defaults" or it's something that users have to specify. You may want to look at either PropertyPlaceholderConfigurer or PropertyOverrideConfigurer: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html that serve as bridge between properties files and `<property>` set via context
ChssPly76
A: 

I would suggest avoiding using File and filesystem related paths. It is usually better to use classpath paths (hmm, no pun intended...) because: - it makes your code testable by segregating classloaders between runtime and test time, something which is routinely done by any decent build system - it makes your code location independent and allows you to ignore OS issues - it makes your code work the same as a standalone app or within a container (lightweight, servlet, app server, whatever...)

You can have a look at the PropertyResourceBundle which has the nice additional feature that is Locale-aware, so you could define different properties with different Locale settings. Note that Locale can be abused to provide parameterization independently of l10n or i18n issues, eg. I used on a project a "windows" and a "linux" locale, because you can construct your own Locale instance and pass it to the loader.

Or you can just construct the path yourself...

Or you can load your Properties from an input stream:

      Properties prop = Properties.load(getClass().getResourceAsStream("/myprops"));

HTH.

insitu
Spring is nice but probably a little bit overkill for such a simple feature. You might have a look at PicoContainer which is a bit more lightweight than Spring as far as DI is concerned
insitu
I problably overlooked your question and gave you an inadequate answer. What I have already done in your particular case is to host the properties to be loaded into a root properties file. Anyway, this information has to be stored somewhere: hardcoded in your code, or in a configuration file. Better use the same mechanism for everything...However, if your properties are tied to class' name, you'd be better off using your second solution but store your properties for easy editing outside of your main source tree and add them in the classpath at runtime.
insitu