12

Java best practices recommends read properties as constants. So, what do you think is the best approach to reach it? My approach is: A Configuration class to read the properties file only one time (singleton pattern) and use this class to read properties when needed as constants. And a Constants class to store:

  • The properties name to find them in the properties file (eg app.database.url).
  • Static constants (those that I don't want the user to config eg CONSTANT_URL="myurl.com").
public final class Configurations {

private Properties properties = null;
private static Configurations instance = null;

/** Private constructor */
private Configurations (){
    this.properties = new Properties();
    try{
        properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(Constants.PATH_CONFFILE));
    }catch(Exception ex){
        ex.printStackTrace();
    }
}   

/** Creates the instance is synchronized to avoid multithreads problems */
private synchronized static void createInstance () {
    if (instance == null) { 
        instance = new Configurations ();
    }
}

/** Get the properties instance. Uses singleton pattern */
public static Configurations getInstance(){
    // Uses singleton pattern to guarantee the creation of only one instance
    if(instance == null) {
        createInstance();
    }
    return instance;
}

/** Get a property of the property file */
public String getProperty(String key){
    String result = null;
    if(key !=null && !key.trim().isEmpty()){
        result = this.properties.getProperty(key);
    }
    return result;
}

/** Override the clone method to ensure the "unique instance" requeriment of this class */
public Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
}}

The Constant class contains the references to the properties and the Constants.

public class Constants {
// Properties (user configurable)
public static final String DB_URL = "db.url";
public static final String DB_DRIVER = "db.driver";

// Constants (not user configurable)
public static final String PATH_CONFFILE = "config/config.properties";
public static final int MYCONSTANT_ONE = 1;
}

And the properties files would be:

db.url=www.myurl.com
db.driver=mysql

To read the properties and constants would be:

// Constants
int i = Constants.MYCONSTANT_ONE;
// Properties
String url = Configurations.getInstance().getProperty(Constants.DB_URL);

Do you think this is a good approach? What is your way to read properties and constants in Java?

Thanks in advance.

Esteban S
  • 1,859
  • 5
  • 22
  • 43

2 Answers2

8

I found a better solution to homogenize the code and has everything as constants. With the same Configurations class and .properties file: Since getInstance() method is static it is possible to init the constants in the class Constants.

A class to store the name to the property in .properties file:

public class Properties {
// Properties (user configurable)
public static final String DB_URL = "db.url";
public static final String DB_DRIVER = "db.driver";
}

And then the Constant class will be:

public class Constants {
// Properties (user configurable)
public static final String DB_URL = Configurations.getInstance().getProperty(Properties.DB_URL);
public static final String DB_DRIVER = Configurations.getInstance().getProperty(Properties.DB_DRIVER );

// Constants (not user configurable)
public static final String PATH_CONFFILE = "config/config.properties";
public static final int MYCONSTANT_ONE = 1;
}

And finally to use them:

// Constants
int i = Constants.MYCONSTANT_ONE;
// Properties
String url = Constants.DB_URL;

I think it is a clean and elegant solution that fix constants and properties problems in tests.

Esteban S
  • 1,859
  • 5
  • 22
  • 43
  • 2
    As Fabien commented its also possible possible put `getProperty` functionality into `getInstance` and rename this as the new `getProperty` to avoid call `getInstance().getProperty` but I leave it this way in the post because it is easier to understand. – Esteban S Apr 28 '15 at 12:37
2

I think you should have a look to Apache Commons Configuration, you could find it useful. You can do a lot of things like having a hierarchy for your config files, specify multiple sources.

For the Constants it seems good :)

Fabien
  • 859
  • 6
  • 15
  • 2
    You're welcome. I proposed you this solution because I know that we sometimes need to have a solution that allows to get properties from different supports. Otherwise the solution you adopted seemed good too. I would just have set the `getProperty` as `static` and included the `getInstance` in it in order to avoid the call to `getInstance` in the method that needs to retrieve the property. – Fabien Apr 28 '15 at 08:26
  • 1
    Thanks for response, its a powerful library for JNDI or XML but in my opinion for simple properties files is preferable the simplicity of java.util. Also its possible to add multiple sources loading new resources and adding with [Properties.putAll](http://docs.oracle.com/javase/7/docs/api/java/util/Hashtable.html#putAll(java.util.Map)) method since java.util.Properties implements Map. – Esteban S Apr 28 '15 at 08:27