Baeldung

Java, Spring and Web Development tutorials

 

Modify Property Files in Java
2025-05-14 18:04 UTC by Stelios Anastasakis

1. Overview

Java Properties are key-value pairs that hold configuration properties needed for application execution. We store these in property files to keep a clean structure. Java provides first-class support for Properties, making it easy to modify Property files and properties in the code.

Java Properties provides a method to store the modified properties, but this core method will overwrite the existing property file. So, we need to find more custom ways to modify existing property files without messing with the whole file.

This article will show how to modify Property files without losing any existing data. We’ll give options to do that using other core Java APIs as well as Apache Commons. Last, we’ll show how to modify XML property files.

2. Project Structure and Utility Classes

Let’s start by creating an interface for property file modifier solutions:

public interface PropertyMutator {
    String getProperty(String key) throws IOException, ConfigurationException;
    void addOrUpdateProperty(String key, String value) throws IOException, ConfigurationException;
}

PropertyMutator contains the signature of the mutators. Each implementation should provide a way to get a property and add a new one, or if it exists, then update the property’s value.

We also create a utility class containing the reusable code for loading Properties from a file:

public class PropertyLoader {
    public Properties fromFile(String filename) throws IOException {
        String appPropertiesFileName = getFilePathFromResources(filename);
        FileInputStream in = new FileInputStream(appPropertiesFileName);
        Properties properties = new Properties();
        properties.load(in);
        in.close();
        return properties;
    }
    public String getFilePathFromResources(String filename) {
        URL resourceUrl = getClass().getClassLoader()
          .getResource(filename);
        Objects.requireNonNull(resourceUrl, "Property file with name [" + filename + "] was not found.");
        return resourceUrl.getFile();
    }
}

Here, we create the class PropertyLoader with a method to load properties from a file that exists in the project resources folder. We also provide the getFilePathFromResources() method to get the file path for a file from the project resources folder:

resources folder structure

The app.properties file is a short file with properties that we’ll be using in our tests:

version=1.0
name=TestApp
date=2016-11-12

We use three properties and validate at the end of each test scenario that the changes we made do not modify or delete any existing property.

3. Modify Property Files Using Java File Streams

Modifying Property Files in Java, if we see it from a different point of view, can also be thought of as just changing a file in Java. Java provides the FileInputStream and FileOutputStream classes of the java.io package to deal with reading and writing to files. We can use these classes to make changes to property files.

Let’s create the implementation of the PropertyMutator, starting with the addOrUpdateProperty method, using the InputFileStream and OutputFileStream classes:

public class FileStreamsPropertyMutator implements PropertyMutator {
    private final String propertyFileName;
    private final PropertyLoader propertyLoader;
    public FileStreamsPropertyMutator(String propertyFileName, PropertyLoader propertyLoader) {
        this.propertyFileName = propertyFileName;
        this.propertyLoader = propertyLoader;
    }
    @Override
    public void addOrUpdateProperty(String key, String value) throws IOException {
        Properties properties = propertyLoader.fromFile(propertyFileName);
        properties.setProperty(key, value);
        FileOutputStream out = new FileOutputStream(propertyLoader.getFilePathFromResources(propertyFileName));
        properties.store(out, null);
        out.close();
    }
    // ... more methods needed to fully implement the interface
}

In the addOrUpdateProperty() method, we first load the properties and then set the new one from the property key and value given as parameters. Finally, we use the FileOutputStream class to store the change.

We can test that the new property was added, without overwriting the file, using JUnit:

@Test
void givenFileStreams_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties()
  throws IOException {
    assertEquals("TestApp", propertyMutator.getProperty("name"));
    assertNull(propertyMutator.getProperty("new.property"));
    propertyMutator.addOrUpdateProperty("new.property", "new-value");
    assertEquals("new-value", propertyMutator.getProperty("new.property"));
    assertEquals("TestApp", propertyMutator.getProperty("name"));
}

In this test, we first assert that the property “name” exists and “new.property” doesn’t. Then, we use the mutator to add this property. Finally, our test validates that the existing property is still there, with its initial value, and the new property is also added, as expected.

Note that the getProperty() method doesn’t cache the properties. It loads them in every call:

@Override
public String getProperty(String key) throws IOException {
    Properties properties = propertyLoader.fromFile(propertyFileName);
    return properties.getProperty(key);
}

This is not the most efficient way from a performance perspective, but we use it to validate that our implementation works as expected.

We can use the same addOrUpdateProperty() method to update the value of an existing property. Let’s use JUnit again to validate the functionality:

@Test
void givenFileStreams_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties()
  throws IOException {
    assertEquals("1.0", propertyMutator.getProperty("version"));
    assertEquals("TestApp", propertyMutator.getProperty("name"));
    propertyMutator.addOrUpdateProperty("version", "2.0");
    assertEquals("2.0", propertyMutator.getProperty("version"));
    assertEquals("TestApp", propertyMutator.getProperty("name"));
}

In this test, we assert the existence and value of two properties, “version” and “name”. Then, we update the value of the first property. Finally, we validate that the updated version has the new value, without any effects on the other existing properties (the second one still exists and has the same value).

4. Modify Property Files Using Apache Commons

Another way to modify property files in Java without overwriting the file is to use the Apache Commons library. This library provides a FileBasedConfigurationBuilder class that offers an easy way to tackle this problem.

But first, let’s include in our pom.xml the dependencies we need to follow this approach:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-configuration2</artifactId>
    <version>2.11.0</version>
</dependency>
<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.10.1</version>
</dependency>

To add a property, we can use the library’s FileBasedConfigurationBuilder class:

public class ApacheCommonsPropertyMutator implements PropertyMutator {
    private final String propertyFileName;
    public ApacheCommonsPropertyMutator(String propertyFileName) {
        this.propertyFileName = propertyFileName;
    }
    @Override
    public void addOrUpdateProperty(String key, String value) throws ConfigurationException {
        FileBasedConfigurationBuilder<FileBasedConfiguration> builder = getAppPropertiesConfigBuilder();
        Configuration configuration = builder.getConfiguration();
        configuration.setProperty(key, value);
        builder.save();
    }
    // ...more methods needed to fully implement the interface
    private FileBasedConfigurationBuilder<FileBasedConfiguration> getAppPropertiesConfigBuilder() {
        Parameters params = new Parameters();
        return new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class).configure(params.properties()
          .setFileName(propertyFileName));
    }
}

First, we implement the getAppPropertiesConfigBuilder() method to get the builder with the Parameters, given a file name that exists in the project properties. We set this file name to the propertyFileName field through the constructor of our class.

Next, in the addOrUpdateProperty() method, we get the builder and retrieve the Configuration object from it. To add a new property, we use the setProperty() method of the configuration object and save the builder.

Last, let’s test our functionality using JUnit:

@Test
void givenApacheCommons_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties()
  throws ConfigurationException {
    assertNull(propertyMutator.getProperty("new.property"));
    assertEquals("TestApp", propertyMutator.getProperty("name"));
    propertyMutator.addOrUpdateProperty("new.property", "new-value");
    assertEquals("new-value", propertyMutator.getProperty("new.property"));
    assertEquals("TestApp", propertyMutator.getProperty("name"));
}

In this test, we start by validating the existence of the “name” property and the non-existence of “new.property”. Then, we use the ApacheCommonsPropertyMutator to add “new.property”. In the end, we check that both properties now exist, without any side effects.

If the property exists, the addOrUpdateProperty() of the ApacheCommonsPropertyMutator class will update this property’s value. A short JUnit test can check if our code works as expected:

@Test
void givenApacheCommons_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties()
  throws ConfigurationException {
    assertEquals("1.0", propertyMutator.getProperty("version"));
    assertEquals("TestApp", propertyMutator.getProperty("name"));
    propertyMutator.addOrUpdateProperty("version", "2.0");
    assertEquals("2.0", propertyMutator.getProperty("version"));
    assertEquals("TestApp", propertyMutator.getProperty("name"));
}

We start by checking the existence of two properties. The next step is to use ApacheCommonsPropertyMutator to update the value of the “version” property. Finally, we validate that the updated value is the expected one, without overwriting the other existing property “name“.

5. Modify Property Files Using Java Files API

Java offers the Files API to deal with files easily. We can take advantage of it and use it to modify property files, ensuring no data is lost.

One caveat with this approach is that using the Files API, we deal with lines, rather than properties. For that reason, the FileAPIPropertyMutator doesn’t implement the PropertyMutator interface, which deals with key-value property pairs.

5.1. Add a Property

When we add a new property using the Files API, we don’t face any issues because we only add one new line at the end of the file:

public class FileAPIPropertyMutator {
    private final String propertyFileName;
    private final PropertyLoader propertyLoader;
    public FileAPIPropertyMutator(String propertyFileName, PropertyLoader propertyLoader) {
        this.propertyFileName = propertyFileName;
        this.propertyLoader = propertyLoader;
    }
    // ... implementation methods
    private List<String> getFileLines() throws IOException {
        File propertiesFile = new File(propertyLoader.getFilePathFromResources(propertyFileName));
        return getFileLines(propertiesFile);
    }
    private List<String> getFileLines(File propertiesFile) throws IOException {
        return new ArrayList<>(Files.readAllLines(propertiesFile.toPath(), StandardCharsets.UTF_8));
    }
}

Next, we have the getFileLines() private method, which comes with an overloaded implementation. We use this method to get the lines of the property file using the Java Files API. We need to first create the File object with the help of the PropertyLoader class and then read the lines using the static Files.readAllLines() method.

Finally, let’s add the addPropertyKeyWithValue() method:

public void addPropertyKeyWithValue(String keyAndValue) throws IOException {
    File propertiesFile = new File(propertyLoader.getFilePathFromResources(propertyFileName));
    List<String> fileContent = getFileLines(propertiesFile);
    fileContent.add(keyAndValue);
    Files.write(propertiesFile.toPath(), fileContent, StandardCharsets.UTF_8);
}

We start by creating the File object because we’ll need it later, and we use the private method to read all the lines of the file. Then, we add the new line and use the static Files.write() method to save the changes. Let’s test using JUnit, similar to the previous examples:

@Test
void givenFilesAPI_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties()
  throws IOException {
    assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1));
    propertyMutator.addPropertyKeyWithValue("new.property=new-value");
    assertEquals("new.property=new-value", propertyMutator.getLastPropertyKeyWithValue());
    assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1));
}

The beginning of the test contains a check that there is some property in the file. We use the method we just created to add the new property. Then, we validate that the new property is present and the existing one wasn’t affected.

5.2. Update an Existing Property’s Value

Updating a property using the Files API is trickier. Since we deal with lines, we need to first locate the line with the property we want to update, then update it, and finally, store the changes without overwriting the whole file:

public int updateProperty(String oldKeyValuePair, String newKeyValuePair) throws IOException {
    File propertiesFile = new File(propertyLoader.getFilePathFromResources(propertyFileName));
    List<String> fileContent = getFileLines(propertiesFile);
    int updatedIndex = -1;
    for (int i = 0; i < fileContent.size(); i++) {
        if (fileContent.get(i)
          .replaceAll("\\s+", "")
          .equals(oldKeyValuePair)) {
            fileContent.set(i, newKeyValuePair);
            updatedIndex = i;
            break;
        }
    }
    Files.write(propertiesFile.toPath(), fileContent, StandardCharsets.UTF_8);
    return updatedIndex;
}

Similar to the addPropertyKeyWithValue() method, we read all lines of the property file. Then, we use a for-loop to navigate over the lines and find the one that has the property with the key and value we’re looking for. After we locate it, we replace it and store it.

Finally, we keep track of the index of the line we updated, to help ourselves in tests:

@Test
void givenFilesAPI_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties()
  throws IOException {
    assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1));
    int updatedPropertyIndex = propertyMutator.updateProperty("version=1.0", "version=2.0");
    assertEquals("version=2.0", propertyMutator.getPropertyKeyWithValue(updatedPropertyIndex));
    assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1));
}

For testing the functionality, we check that the “name” property exists, update the “version” value, and finally, validate that the “version” contains the updated value and “name” is not affected.

6. Modify XML Property Files

To modify property files in Java, when dealing with XML files, we follow a similar approach to the previous ones, but we use the loadFromXML() and storeToXML() methods of Properties. Let’s implement the PropertyMutator interface for XML files:

public class XMLFilePropertyMutator implements PropertyMutator {
    private final String propertyFileName;
    public XMLFilePropertyMutator(String propertyFileName) {
        this.propertyFileName = propertyFileName;
    }
    // ... implementation methods
    private Properties loadProperties() throws IOException {
        return loadProperties(getXMLAppPropertiesWithFileStreamFilePath());
    }
    private Properties loadProperties(String filepath) throws IOException {
        Properties props = new Properties();
        try (InputStream is = Files.newInputStream(Paths.get(filepath))) {
            props.loadFromXML(is);
        }
        return props;
    }
    String getXMLAppPropertiesWithFileStreamFilePath() {
        URL resourceUrl = getClass().getClassLoader()
          .getResource(propertyFileName);
        Objects.requireNonNull(resourceUrl, "Property file with name [" + propertyFileName + "] was not found.");
        return resourceUrl.getFile();
    }
}

The field propertyFileName will hold the name of the XML file with the properties, from the project resources folder. For reading the properties, we implement some private methods, similar to what we did with file streams. The difference is that we need to use the Properties method loadFromXML() and pass in the input stream.

The XML properties file that we’re going to use in our tests is icons.xml:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>xml example</comment>
    <entry key="fileIcon">icon1.jpg</entry>
    <entry key="imageIcon">icon2.jpg</entry>
    <entry key="videoIcon">icon3.jpg</entry>
</properties>

Let’s see how to add a new property in the XML file by combining the relevant methods from Properties, Files, and OutputStream:

@Override
public void addOrUpdateProperty(String key, String value) throws IOException {
    String filePath = getXMLAppPropertiesWithFileStreamFilePath();
    Properties properties = loadProperties(filePath);
    try (OutputStream os = Files.newOutputStream(Paths.get(filePath))) {
        properties.setProperty(key, value);
        properties.storeToXML(os, null);
    }
}

We start by reading the properties, using the private methods we created earlier. Then, we add the new property and use the OutputStream with the storeToXML() method to store the value. Moving forward, let’s test this functionality using JUnit:

@Test
void givenXMLPropertyFile_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties()
  throws IOException {
    assertEquals("icon1.jpg", propertyMutator.getProperty("fileIcon"));
    assertNull(propertyMutator.getProperty("new.property"));
    propertyMutator.addOrUpdateProperty("new.property", "new-value");
    assertEquals("new-value", propertyMutator.getProperty("new.property"));
    assertEquals("icon1.jpg", propertyMutator.getProperty("fileIcon"));
}

We start by asserting that the property “fileIcon” exists but “new.property” doesn’t. We add the property using the addOrUpdateProperty() method we implemented and assert that the “new.property” now exists and that the “fileIcon” is not affected by the changes.

The Properties’ method setProperty() will update the property’s value when it exists. To validate the behavior, we use a JUnit test:

@Test
void givenXMLPropertyFile_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties()
  throws IOException {
    assertEquals("icon1.jpg", propertyMutator.getProperty("fileIcon"));
    assertEquals("icon2.jpg", propertyMutator.getProperty("imageIcon"));
    propertyMutator.addOrUpdateProperty("fileIcon", "icon5.jpg");
    assertEquals("icon5.jpg", propertyMutator.getProperty("fileIcon"));
    assertEquals("icon2.jpg", propertyMutator.getProperty("imageIcon"));
}

First, we check two of the existing properties, then we update the value of one, and finally, we assert that the updated property contains the new value and the other property still exists, with the same value.

7. Conclusion

In this article, we talked about Java Properties. We went through how to modify property files in Java and store the changes, without overwriting the rest of the properties in the file. Last, we saw a more specific example of how to modify XML property files.

As always, all the source code used in the examples can be found over on GitHub.

The post Modify Property Files in Java first appeared on Baeldung.
       

 

Content mobilized by FeedBlitz RSS Services, the premium FeedBurner alternative.