Java Properties files can contain duplicate key entries. This can be a problem since the Java Properties loader will just keep the last value parsed.
Not a problem for small applications, but when property files grow in number and size this can become a maintenance issue. Fortunately there are many solutions for this (I hope). This post will present a very simple method that performs duplicate key detection.
When first confronted with dupe detection goal, reading the Properties file directly and determining dupes using a HashMap sounds simple. However, you would have to duplicate the Properties file format parsing. That can get complex. For example, a property entry may use “:” or “=” to specify the key, value pair. Plus, you would have to handle the line continuations feature, and other requirements.
Commons Configuration makes this simple since its Properties loader will create lists for any duplicate property key. Thus, to detect duplicates, just find which property values are lists, see listing 1 below.
Listing 1, Duplicate key detection using Commons Config Also available as a Gist
package com.octodecillion.util; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; /** * Detect duplicate properties when loading Properties from stream. * <p> * * @author jbetancourt * @since */ public class DuplicatePropDetectWithCommonsConfig { /** * Detect duplicate keys in Properties resource. * <p> * <a href="">Commons Config</a> is used. * {@link Properties} class. * * @see Properties#load(Reader) * * @param reader The reader is NOT closed. * @param delimiterParsingDisabled * @return Map of keys that are duplicated with a list value of each value of duplicate. * @throws ConfigurationException */ @SuppressWarnings("unchecked") public Map<String, List<String>> loadWithConfig(Reader reader, boolean delimiterParsing) throws ConfigurationException { PropertiesConfiguration config = new PropertiesConfiguration(); final Map<String, List<String>> results = new HashMap<>(); config.setDelimiterParsingDisabled(delimiterParsing); config.load(reader); Iterator<String> keys = config.getKeys(); while (keys.hasNext()) { String theKey = keys.next(); Object valueObject = config.getProperty(theKey); if (!(valueObject instanceof String)) { results.put(theKey, (List<String>) valueObject); } } return results; } /** * @author jbetancourt * */ @RunWith(Enclosed.class) public static class DuplicatePropDetectWithCommonsConfigTest { private static final String DATA1_PROPERTIES = "/Data1.properties"; /** * @throws ConfigurationException */ @Test public void testLoadFileWithConfig() throws ConfigurationException { InputStream is = this.getClass().getResourceAsStream(DATA1_PROPERTIES); Assert.assertNotNull(is); DuplicatePropDetectWithCommonsConfig detector = new DuplicatePropDetectWithCommonsConfig(); Map<String, List<String>> map = detector.loadWithConfig(new InputStreamReader(is), true); Assert.assertEquals(1, map.size()); Assert.assertTrue(map.containsKey("three")); } } }
Links
