24

Is it possible to stack loaded properties in Java? For instance can I do:

Properties properties = new Properties();

properties.load(new FileInputStream("file1.properties"));
properties.load(new FileInputStream("file2.properties"));

and access properties from both?

tshepang
  • 12,111
  • 21
  • 91
  • 136
travega
  • 8,284
  • 16
  • 63
  • 91
  • 2
    Yes, if the properties have different names. No, if the properties have the same names. If the property names clash, you will have to provide the stacking yourself. – Jesse Apr 16 '12 at 20:37

6 Answers6

44

You can do this:

Properties properties = new Properties();

properties.load(new FileInputStream("file1.properties"));

Properties properties2 = new Properties();
properties2.load(new FileInputStream("file2.properties"));

properties.putAll(properties2);

NOTE : All the keys maintained are unique. So, the later properties loaded with same key will be overridden. Just to keep for your ref :)

Eugene Retunsky
  • 13,009
  • 4
  • 52
  • 55
  • 8
    If file2.properties contains properties with the same names as properties defined in file1.properties, then only the values for those properties in file2.properties will be present. – Jesse Apr 16 '12 at 20:35
  • Right. You cannot keep both properties at a time, as keys must be unique. – Eugene Retunsky Apr 16 '12 at 20:38
  • The recommended way is to pass the default properties file in the constructor. That Properties extends Map is just a an implementation detail. – Puce Apr 16 '12 at 20:39
  • @Puce - `Properties` doesn't have a constructor with a file name as a parameter. – Eugene Retunsky Apr 16 '12 at 20:44
  • @EugeneRetunsky No, but it has a constructor taking another Properties object, which can be loaded from another file. – Puce Apr 16 '12 at 20:48
  • @Puce why we need to load Properties first then create another instance of Properties from the loaded instance instead of simply using the first one? Probably I might have misunderstood you. Can you provide a code example? – Eugene Retunsky Apr 16 '12 at 20:51
  • @EugeneRetunsky I've updated my answer with a code sample. The constructor is the designed API. The fact that it extends Hashtable and thus could have key/ values other than String is an implementation detail which never should have been exposed to the API (composition instead of inheritance). – Puce Apr 16 '12 at 21:09
  • 3
    What you say is true, but it does not answer the question asked by the post originator. The answer from @tskuzzy is actually the correct answer. – Eric Green Dec 13 '19 at 06:07
  • @EricGreen you're right. However, it's not explicitly stated if `load` overwrites or preserves previous values. So it's debatable which approach should be preferred (and if it raises such a question, then it's better to be explicit, IMO). – Eugene Retunsky Dec 18 '19 at 03:52
12

Yes the properties stack. Properties extends Hashtable and load() simply calls put() on each key-value pair.

Relevant code from the Source:

String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf); 
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf); 
put(key, value); 

In other words, loading from a file doesn't clear the current entries. However, note that if the two files contain entries with the same key, the first one will be overwritten.

tskuzzy
  • 35,812
  • 14
  • 73
  • 140
  • The recommended way is to pass the default properties file in the constructor. That Properties extends Map is just a an implementation detail. – Puce Apr 16 '12 at 20:42
  • 1
    This behavior is not declared by the `Properties` contract (in other words, this is not documented with all possible consequences of using undocumented features). – Eugene Retunsky Apr 16 '12 at 20:43
  • This is true and should be taken into consideration. I was merely interested in the actual results rather than documented behavior. – tskuzzy Apr 16 '12 at 20:47
  • "`Properties` extends `java.util.Hashtable`." (source: https://docs.oracle.com/javase/tutorial/essential/environment/properties.html) – payne Nov 30 '20 at 20:13
5

Actually, yes. You can do this. If any of the properties overlap, the newer loaded property will take place of the older one.

Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
2

Yes, you need to pass the default properties file in the constructor. Like this you can chain them up.

E.g.:

Properties properties1 = new Properties();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file1.properties"))){
    properties1.load(bis);
}

Properties properties2 = new Properties(properties1);
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file2.properties"))){
    properties2.load(bis);
}
Puce
  • 37,247
  • 13
  • 80
  • 152
  • I liked this at first, but now I have reservations. Putting aside the use of BufferedInputStream, how is this better than the OP's code? In both cases, you are loading the second file directly into a Properties object that contains the first file's properties. But in this example, you are creating a new property object. What's the benefit? – datguy Jul 17 '14 at 15:23
  • If you use this method, and are iterating over the properties for some reason, you **must** use the `propertyNames()` or `stringPropertyNames()` to get the list to iterate over. If you use the underlying `Map` methods like `entrySet()` or `keySet()`, the properties specified in the constructor will not be included. – Scott McIntyre Aug 10 '16 at 15:46
1

This should also work. If same property is defined in file1.properties and file2.properties, property in file2.properties will be in effect.

    Properties properties = new Properties();
    properties.load(new FileInputStream("file1.properties"));
    properties.load(new FileInputStream("file2.properties"));

Now the properties map will have properties from both files. If same key appears in file1 and file2, the value of the key from file1 will be updated in properties with value in file2 since I'm calling file1 then file2.

John
  • 306
  • 3
  • 3
1

You can do this a little more dynamical, working with an indeterminate number of files.

The parameter for this method should be a list with the path to the property file. I made the method static, put it on a class with other message handling related functions, and simply call it when I need it:

public static Properties loadPropertiesFiles(LinkedList<String> files) {
    try {
        Properties properties = new Properties();

                for(String f:files) {
                    Resource resource = new ClassPathResource( f );
                    Properties tempProp = PropertiesLoaderUtils.loadProperties(resource);
                    properties.putAll(tempProp);
                }
                return properties;
    }
    catch(IOException ioe) {
                return new Properties();
    }
}
Carrol
  • 1,225
  • 1
  • 16
  • 29