views:

1541

answers:

5

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?

+4  A: 

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.

Jon Skeet
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
Just a quick correction, Java does have a implementation of Map, LinkedHashMap, that DOES maintain insertion order.
James McMahon
@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.
Jon Skeet
extend Properties, override put() and store the keys in an internal List. use said list to iterate the properties in order.
james
+1  A: 

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

Clint
Yes, that had occurred to me. That might be the simplest workaround.
James McMahon
Probably not going to give what you want though as string sortable doesn't match integer sortable for mixed strings. 11-SomePropName will sort before 2-OtherPropName if you're sorting strings by their natural sort value.
Chris Kessel
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
+3  A: 

Apache Commons Configuration might do the trick for you. I haven't tested this myself, but I checked their sources and looks like property keys are backed by LinkedList in AbstractFileConfiguration class:

public Iterator getKeys()
{
    reload();
    List keyList = new LinkedList();
    enterNoReload();
    try
    {
        for (Iterator it = super.getKeys(); it.hasNext();)
        {
            keyList.add(it.next());
        }

        return keyList.iterator();
    }
    finally
    {
        exitNoReload();
    }
}
serg
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.
James McMahon
A: 

It's quite simple. You just have to extend Properties and override both put() and keys() methods.

E.g.

class LinkedProperties extends Properties {

    private final LinkedHashSet<Object> keys = new LinkedHashSet<Object>();

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

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

You must inherit also keySet() if you want to export Properties as XML:

public Set<Object> keySet() { return keys; }