11

I chose to take properties file for customization of some settings. I use the following code to make a Properties Object available in a class

Properties defaultProps = new Properties();
    try {
        FileInputStream in = new FileInputStream("custom.properties");
        defaultProps.load(in);
        in.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

Do I have to add this to every class? Probably not because then every class would open a stream to this file. But I'm not sure how to handle this properly. Should I make a class MyProperties and instantiate it in whatever class needs properties?

Thanks in advance!

In silico
  • 51,091
  • 10
  • 150
  • 143
tzippy
  • 6,458
  • 30
  • 82
  • 151
  • Related answer: http://stackoverflow.com/questions/4362911/how-to-create-a-singleton-class/4363254#4363254 – BalusC Jan 20 '11 at 17:06

8 Answers8

14

Once you initialized defaultProps, you can make its contents available to other objects in your app e.g. via a public static accessor method, e.g.:

public class Config {
  private static Properties defaultProps = new Properties();
  static {
    try {
        FileInputStream in = new FileInputStream("custom.properties");
        defaultProps.load(in);
        in.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
  public static String getProperty(String key) {
    return defaultProps.getProperty(key);
  }
}

This is the simplest approach, however it creates an extra dependency which makes unit testing harder (unless you provide a method in Config to set a mock property object for unit testing).

An alternative is to inject defaultProps (or individual configuration values from it) into each object which needs it. However, this may mean you need to add extra parameter(s) to lots of methods if your call hierarchies are deep.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • 1
    I don't like this solution. Making the method non-static and creating a singleton makes it much more flexible and costs nothing. – maaartinus Jan 20 '11 at 17:09
  • @maaartinus: how exactly is applying the singleton pattern more flexible? Aren't you confusing it with the abstract factory pattern? – BalusC Jan 20 '11 at 17:10
  • 1
    @maaartinus, how would a Singleton make this more flexible? Note that practically this is already a singleton (it's a unique global object, with all its dependency baggage), just hidden behind an interface. – Péter Török Jan 20 '11 at 17:12
  • Well, I consider a singleton only a *real* singleton when it's been lazily loaded on first access. That's also the whole intent of the singleton pattern. Otherwise there's just means of "just create one" pattern. – BalusC Jan 20 '11 at 17:30
  • @BalusC, I have never heard that lazy loading would be a requirement for being a "real" Singleton (although surely it is often used in conjunction with it). Anyway, it would be fairly trivial to modify the above example to load the properties lazily. But I feel that the OP would not need to get confused by even more technical details and tricks :-) – Péter Török Jan 20 '11 at 17:37
  • Agreed, a real singleton is as flexible as using static methods. However, it's much easier to turn into something better. You can do it in small steps by replacing usage of MySingleton.getInstance() by passing the object as e.g. ctor parameter. This way I once eliminated a couple of singletons and ended with nice DI. When starting with static methods, you may want to convert it to a singleton first and then continue as above. – maaartinus Jan 20 '11 at 17:49
  • @maaartinus, you can do the same directly with a static method. If you personally prefer Singletons, I don't mind a bit, but technically there is no real difference. – Péter Török Jan 21 '11 at 08:21
  • I can NOT! I can't replace all calls to static Config.getSomething in one class by non-static method calls config.getSomething and leave them alone elsewhere. Unless I write a new class/method. The easiest way to do such small steps towards DI is to start with the transformation to singleton. That said, singletons are evil, too. Or can you show me why am I wrong? – maaartinus Jan 21 '11 at 08:50
  • @maaartinus, I really don't see the fundamental difference between a) eliminating a call to `Config.getInstance().getProperty("foo")` by injecting a method parameter `String fooParameter`, and b) eliminating a call to `Config.getProperty("foo")` using the same method parameter. – Péter Török Jan 21 '11 at 09:23
  • OK, now I understand. However, you can't inject an instance of Config and use it, which is a less painful step. Actually, for configurations may the direct injection of fooParameter be better (Law of Demeter), but normally you don't want to disassemble your class. – maaartinus Jan 21 '11 at 09:36
  • 1
    To avoid your dependency problem, consider implementing dependency injection using a factory method pattern. See this answer for an example http://stackoverflow.com/a/27724421/2048879 – ben_frankly Jul 29 '15 at 21:52
3

If you only need one instance of your properties class you can use the singleton (anti?)-pattern.

It would look like a class like this:

public class MyProperties extends Properties {
    private static MyProperties instance = null;

    private MyProperties() {
    }

    public static MyProperties getInstance() {
        if (instance == null) {
            try {
                instance = new MyProperties();
                FileInputStream in = new FileInputStream("custom.properties");
                instance.load(in);
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        return instance;
    }
}
SirDarius
  • 41,440
  • 8
  • 86
  • 100
1

Why not use a static ResourceBundle ?

static final ResourceBundle myResources = 
          ResourceBundle.getBundle("MyResources", currentLocale);
fmucar
  • 14,361
  • 2
  • 45
  • 50
0

Rather than loading properties in every class. Load it somewhere around main() and pass it to other classes via their constructors.

Don't share them globally. - Difficult to test - Against the abstraction (Global access, DAO can access user settings. it should be prevented by passing only what it needs.. not everything) - Classes lie what they need

Nilesh
  • 2,089
  • 3
  • 29
  • 53
0

There's too little information to determine what the best way to handle this would be. You may want to expose it using an accessor, or pass it into each class that requires it. Alternatively, you may pull out the properties that each class needs and pass their values into the class's constructor.

Kent Murra
  • 234
  • 1
  • 2
0

Load the properties once using and store the Properties somewheres that others classes can pull from. If that is a MyProperties class that references a static variable somewhere that is fine.

jzd
  • 23,473
  • 9
  • 54
  • 76
0

This is a special case of making anything available globally. Using static methods is quite bad. A better but bad solution is using the sigleton pattern. Testing is the greatest problem here. IMHO, the best way is using Dependency injection, although it may be an overkill for small applications.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
0

Since this information is static across all instances, I recommend implementing the Properties class as a singleton. By using the static initialization block method, you can have it load the file automatically when the program starts up.

public class Properties {
  static {
    try {
      FileInputStream in = new FileInputStream("custom.properties");
      load(in);
      in.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  protected static void load(FileInputStream in) {
    // existing load functionality here
  }
}

You are still going to need an internal storage mechanism and accessor mechanism. These should also be marked static.

Courtney Christensen
  • 9,165
  • 5
  • 47
  • 56