Reloadable property file

There are still applications out there which require a restart after changing user settings, but more commonly the user settings are being observed by a “reloadable property configuration”. If the user edits the settings file, the application will notice and reload the settings.

Tasked with implementing such a feature for a fairly straight-forward YAML file, I came across Apache Commons Configuration2. It is super-powerful, with stuff like JNDI, JDBC, XML, .properties format etc. Of which which we don’t need a single one. There’s a section on reloading, with configurable strategies, serialization managers and whatnot.

What we’re looking for:

  • Simply de-/serialization between YAML and Java bean
  • allows to serialize/store settings from Java bean to YAML, ie. the user edits settings within the application
  • allows to reload settings when the user edits the settings file directly

Luckily Jackson now provides a YAML extension


and Java NIO has the very handy java.nio.file.WatchService, so we come up with

 * Created on 20 Jul 2018
package ch.want.demos;

import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

public class UserPropertiesManager {

    private static final Logger LOG = LoggerFactory.getLogger(UserPropertiesManager.class);
    private UserProperties userProperties; // this is our configuration Java bean
    private final ObjectMapper mapper;
    private File propertiesFile;

    public UserPropertiesManager() {
        mapper = new ObjectMapper(new YAMLFactory());

    public void init() {

    private void initPropertyFileReference() {
        propertiesFile = new File("config/settings.yml");

    private void readPropertiesFromFile() {
        LOG.debug("Reading configuration from {}", propertiesFile);
        try {
            final UserProperties newProperties = mapper.readValue(propertiesFile, UserProperties.class);
            new Thread(new ConfigurationEditWatcher()).start();
        } catch (final IOException e) {
            LOG.error(e.getMessage(), e);

    public void writePropertiesToFile() {
        LOG.debug("Storing configuration to {}", propertiesFile);
        try {
            mapper.writeValue(propertiesFile, userProperties);
        } catch (final IOException e) {
            LOG.error(e.getMessage(), e);

    private class ConfigurationEditWatcher implements Runnable {

        private final WatchService watcher;
        private final Path configDir;

        ConfigurationEditWatcher() throws IOException {
            watcher = FileSystems.getDefault().newWatchService();
            configDir = Paths.get(propertiesFile.getParentFile().toURI());
            configDir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);

        public void run() {
            try {
                WatchKey key;
                while ((key = watcher.take()) != null) {
            } catch (final InterruptedException | IOException ex) { // NOSONAR
      "Terminating WatchService on configuration file");

        private void processWatchKey(final WatchKey key) throws IOException {
            for (final WatchEvent event : key.pollEvents()) {
                if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                    processWatchEvent((WatchEvent) event);

        private void processWatchEvent(final WatchEvent pathEvent) throws IOException {
            final Path filename = pathEvent.context();
            final Path modifiedFile = configDir.resolve(filename);
            if (Files.isSameFile(modifiedFile, propertiesFile.toPath())) {

All we wanted in one simple class. Hope this helps whoever’s reading this.

In the process of developing, a corporate post-booking travel management tool, I’m sharing some hopefully useful insights into Angular 4, Spring Boot, jOOQ, or any other technology we’ll be using.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s