Pulling values from a Java Properties file in order?

47,269

Solution 1

If you can alter the property names your could prefix them with a numeral or other sortable prefix and then sort the Properties KeySet.

Solution 2

Extend java.util.Properties, override both put() and keys():

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.HashMap;

public class LinkedProperties extends Properties {
    private final HashSet<Object> keys = new LinkedHashSet<Object>();

    public LinkedProperties() {
    }

    public Iterable<Object> orderedKeys() {
        return Collections.list(keys());
    }

    public Enumeration<Object> keys() {
        return Collections.<Object>enumeration(keys);
    }

    public Object put(Object key, Object value) {
        keys.add(key);
        return super.put(key, value);
    }
}

Solution 3

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.

Solution 4

Working example :

Map<String,String> properties = getOrderedProperties(new FileInputStream(new File("./a.properties")));
properties.entrySet().forEach(System.out::println);

Code for it

public Map<String, String> getOrderedProperties(InputStream in) throws IOException{
    Map<String, String> mp = new LinkedHashMap<>();
    (new Properties(){
        public synchronized Object put(Object key, Object value) {
            return mp.put((String) key, (String) value);
        }
    }).load(in);
    return mp;
}

Solution 5

Dominique Laurent's solution above works great for me. I also added the following method override:

public Set<String> stringPropertyNames() {
    Set<String> set = new LinkedHashSet<String>();

    for (Object key : this.keys) {
        set.add((String)key);
    }

    return set;
}

Probably not the most efficient, but it's only executed once in my servlet lifecycle.

Thanks Dominique!

Share:
47,269
James McMahon
Author by

James McMahon

Blogging at https://dev.to/jamesmcmahon.

Updated on July 27, 2020

Comments

  • James McMahon
    James McMahon almost 4 years

    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 original file.

    However, since the Properties file is backed by, correct me if I'm wrong, a Map that does not maintain insertion order, the iterator returns the values in the wrong order.

    Here is the code I'm using

    Enumeration names = propfile.propertyNames();
    while (names.hasMoreElements()) {
        String name = (String) names.nextElement();
        //do stuff
    }
    

    Is there anyway to get the Properties back in order short of writting my own custom file parser?

  • James McMahon
    James McMahon over 14 years
    I was afraid of that. I'm looking at the Properties code right now and I see exactly what you mean. The backing implementation should really should be a settable delegate. Can you recommend any alternatives? Like would the Apache Commons configuration help me out?
  • James McMahon
    James McMahon over 14 years
    Just a quick correction, Java does have a implementation of Map, LinkedHashMap, that DOES maintain insertion order.
  • Jon Skeet
    Jon Skeet over 14 years
    @nemo: Yes, but that's a map specifically designed for that. Maps in general aren't ordered. I believe Spring has its own properties file reader which you might find useful.
  • James McMahon
    James McMahon over 14 years
    Yes, that had occurred to me. That might be the simplest workaround.
  • james
    james over 14 years
    extend Properties, override put() and store the keys in an internal List. use said list to iterate the properties in order.
  • James McMahon
    James McMahon over 14 years
    This is actually what I ended up doing. I was only dealing with four values and commons configuration need too many dependencies which would have complicated my build.
  • James McMahon
    James McMahon over 14 years
    This looks interesting, but the using one piece of the commons requires loading several other pieces. I ended up going with a quick and dirty solution.
  • Emmanuel Bourg
    Emmanuel Bourg over 12 years
    Most of the dependencies are optional. For a simple PropertiesConfiguration you only need Commons Lang and Commons Collections.
  • Jordy Boom
    Jordy Boom almost 12 years
    It would be safer to create your class as a wrapper around Properties, rather than extending it. Only overriding those methods makes assumptions about how the underlying class works (the assumption that putAll() uses put()), and you could run into situations where your keys set is incorrect.
  • Michael Wyraz
    Michael Wyraz over 11 years
    You should really override remove() and clear() as well - otherwise you'll get NullPointerExceptions on save()! Also you should add synchronized as it is in the parent's methods unless the collection used for the keys is thread safe.
  • mirelon
    mirelon about 10 years
    the type can be inferred in return Collections.<Object>enumeration(keys);, so this is sufficient: return Collections.enumeration(keys);
  • Milson
    Milson almost 9 years
    [DataMember(Name = "attribute ID", Order = 0)] private int _attributeID; can't we have such thing in Java
  • javaPhobic
    javaPhobic over 8 years
    The problem with this approach is, the original Properties class supports more than just the simple example "test=test2" when loading. For example, data can have "=", you can use escapes for special characters etc. Writing your own class means you have to implement a whole lot more.
  • AlikElzin-kilaka
    AlikElzin-kilaka over 7 years
    Explaining the code: The trick is to use Java's Properties class, override it's put method and put the key into a data structure that saves the order of insertion. This works because Properties puts the keys/values at the same order it reads them from the file - top->bottom.
  • walkeros
    walkeros over 7 years
    -1 - You assume that the put method is called according to the order of properties in the source file. I think you can not assume that this is guaranteed. If the file was read from bottom to top you will get the properties in reversed order.
  • Jaison Varghese
    Jaison Varghese about 6 years
    However this method sorts the entries alphabetically and doesn't guarantee insertion order (the order of the original file)
  • Joter
    Joter about 4 years
    Thanks!!!! It resolve my problem to save in same order as it present in the file.