Developer

Enhance persistent application properties in your Java application

Maintaining persistent data is a common feature of Java applications. The basic Properties class provides the necessary functionality, but you can easily enhance this class to provide additional features. Find out how.


Most software applications require a persistent set of properties for normal execution. The Properties class in the java.util package is often used for such storage. It provides a convenient mechanism for storing properties. But sometimes you need a more complicated property file structure, which you can achieve by expanding the Properties class.

The Properties class stores data as key-value pairs that don't allow duplicates, but duplication is often desired. It is, however, still possible to use the standard Properties class to achieve this by splitting the same entries into different files and copying the same values for different keys. Unfortunately, this solution is error prone and can be tedious to modify. A simple workaround is the PropertiesExpansion class that allows expanding properties with the "${}" tag to eliminate data repetition. It also allows you to use the same entries within one property file by keeping them in different sections.

Expanding properties
The main purpose of the property expansion is to make data represented in a property file clearer and easier to maintain. To achieve this, you use the “${}” tag to introduce substitutable parameters, so they can be expanded to values indicated with tag names during property retrieval at runtime. Here is the example of a property file with substitution tags.
 
user.name=john
home.dir=usr
working.dir=${home.dir}/tmp

 

When accessing these properties, the ${home.dir} tag is substituted with the usr value, so the working.dir property is usr/tmp. Examine the PropertiesExpansion class in Listing A that inherits from java.util.Properties. To provide tag expansion, the getProperty(String key), setProperty(String key,String value), and load(InputStream is) methods of the standard Properties class is overridden and the replace() method is added.

There are two overloaded replace() methods in Listing A. One replaces all substitution tags with the corresponding values from the current property list. The other replace(String in,Hashtable keys) method is a convenient static method to perform the same replacement with a Hashtable object containing substitution tags.

The setProperty(), load() and getProperty() methods are overwritten in such a way that they check whether or not a value mapped for a given key contains expansion tags. If tags are found, they are replaced with corresponding values.

Sectioning properties
In some situations, it is useful to have keys with same names mapped to different values. You can do this by sectioning a property file like this:
 
# global properties
section.root=root
x1=2
y1=0
[user.1]
x1=${x1}
y1=10
[${section.root}]
x1=123
y2=20

 

All key-value pairs above the user.1 section are the global parameters that may be referred from different sections for value substitution. For example, after property expansion, the ${section.root} section becomes root and the property x1 in the user.1 section becomes 2.

If you need to retrieve a named property from a given section, use the getProperty(String section,String key) method. It accepts a section name as an additional parameter. Each section name is mapped to a Properties object containing key-value pairs. To get a value of the property x1 from the user.1 section, execute the code in Listing B with the following line:
 
PropertiesExpansion.getProperty(“user.1”,”x1”)

The setProperty() method in Listing B is used to set a key-value pair for a desired section. This method calls the Hashtable’s put() method which is overridden by the PropertiesExpansion class. The trick is the put() method determines which section a key-value pair belongs to and updates this section correspondingly. Direct use of the put() method to set properties is strongly discouraged as it allows inserting entries whose keys or values are not strings.

You can retrieve all section names by calling the sections() method, which returns an enumeration of section names. All keys belonging to a section are retrieved by calling the sectionKeys() method. The store() method is overwritten, so it writes properties into a file using their position within sections.

There are additional methods such as getInt(), getLong(), getFloat(), getDouble(), and getBoolean() to simplify the casting of property values to primitive types such as int, long, float, double, and Boolean. These methods accept an additional Properties object containing a value for a given key.

 

 

 

Editor's Picks