I have a properties file where the order of the values is important. I want to be able to iterate through the properties file and output the values based on the order of the
Nope - maps are inherently "unordered".
You could possibly create your own subclass of Properties
which overrode setProperty
and possibly put
, but it would probably get very implementation-specific... Properties
is a prime example of bad encapsulation. When I last wrote an extended version (about 10 years ago!) it ended up being hideous and definitely sensitive to the implementation details of Properties
.
For those who read this topic recently: just use class PropertiesConfiguration from org.apache.commons:commons-configuration2. I've tested that it keeps properties ordering (because it uses LinkedHashMap internally). Doing:
`
PropertiesConfiguration properties = new PropertiesConfiguration();
properties.read(new FileReader("/some/path));
properties.write(new FileWriter("/some/other/path"));
`
only removes trailing whitespace and unnecessary escapes.
An alternative is just to write your own properties file using LinkedHashMap, here is what I use :
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
public class OrderedProperties {
private static Map<String, String> properties = new LinkedHashMap<String, String>();
private static OrderedProperties instance = null;
private OrderedProperties() {
}
//The propertyFileName is read from the classpath and should be of format : key=value
public static synchronized OrderedProperties getInstance(String propertyFileName) {
if (instance == null) {
instance = new OrderedProperties();
readPropertiesFile(propertyFileName);
}
return instance;
}
private static void readPropertiesFile(String propertyFileName){
LineIterator lineIterator = null;
try {
//read file from classpath
URL url = instance.getClass().getResource(propertyFileName);
lineIterator = FileUtils.lineIterator(new File(url.getFile()), "UTF-8");
while (lineIterator.hasNext()) {
String line = lineIterator.nextLine();
//Continue to parse if there are blank lines (prevents IndesOutOfBoundsException)
if (!line.trim().isEmpty()) {
List<String> keyValuesPairs = Arrays.asList(line.split("="));
properties.put(keyValuesPairs.get(0) , keyValuesPairs.get(1));
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
lineIterator.close();
}
}
public Map<String, String> getProperties() {
return OrderedProperties.properties;
}
public String getProperty(String key) {
return OrderedProperties.properties.get(key);
}
}
To use :
OrderedProperties o = OrderedProperties.getInstance("/project.properties");
System.out.println(o.getProperty("test"));
Sample properties file (in this case project.properties) :
test=test2
As I see it, Properties
is to much bound to Hashtable
. I suggest reading it in order to a LinkedHashMap
. For that you'll only need to override a single method, Object put(Object key, Object value)
, disregarding the Properties
as a key/value container:
public class InOrderPropertiesLoader<T extends Map<String, String>> {
private final T map;
private final Properties properties = new Properties() {
public Object put(Object key, Object value) {
map.put((String) key, (String) value);
return null;
}
};
public InOrderPropertiesLoader(T map) {
this.map = map;
}
public synchronized T load(InputStream inStream) throws IOException {
properties.load(inStream);
return map;
}
}
Usage:
LinkedHashMap<String, String> props = new LinkedHashMap<>();
try (InputStream inputStream = new FileInputStream(file)) {
new InOrderPropertiesLoader<>(props).load(inputStream);
}
If you can alter the property names your could prefix them with a numeral or other sortable prefix and then sort the Properties KeySet.
Map<String, String> mapFile = new LinkedHashMap<String, String>();
ResourceBundle bundle = ResourceBundle.getBundle(fileName);
TreeSet<String> keySet = new TreeSet<String>(bundle.keySet());
for(String key : keySet){
System.out.println(key+" "+bundle.getString(key));
mapFile.put(key, bundle.getString(key));
}
This persist the order of property file