Creation of configuration instances
Configuration sources
Interface Config provides static methods for start fluent creation of
configuration instances from different sources.
All configuration builders support additional options described in the Shared options section.
Environment variables
Configuration instance that retrieves values from environment variables
(System.getenv()) can be created using the
Config.fromEnvironmentVariables() method.
Example:
Config config = Config.fromEnvironmentVariables()
.build();
String path = config.get("PATH");
This configuration source is read-only.
System properties
Configuration instance that retrieves values from system properties
(System.getProperties()) can be created using the
Config.fromSystemProperties() method.
Example:
Config config = Config.fromSystemProperties()
.build();
String userHome = config.get("user.home");
This configuration source is read-only.
Java Properties
Configuration instance that uses Java Properties as storage mechanism
can be created using the Config.fromProperties() method.
Example:
Map<String, String> localValues = ...;
Config config = Config.fromProperties()
.load("example/config.properties")
.add(localValues) // Overrides loaded properties
.build();
String host = config.get("host");
This configuration source supports watchable mutable configurations that can be persisted on files or output streams.
Example:
Map<String, String> localValues = ...;
FileWatchableConfig config = Config.fromProperties()
.load("example/config.properties")
.add(localValues) // Overrides loaded properties
.mutable()
.build();
config.set("host", "example.com");
config.remove("timeout");
Path path = ...;
config.save(path);
JSON
Jackson 2 based configuration instance that retrieves values from JSON files
or objects can be created using the Config.fromJson() method.
Note: Requires Jackson 2.x com.fasterxml.jackson.core:jackson-databind
dependency.
The library declares dependency as optional, so it must be included explicitly
in the project dependencies.
Example:
Map<String, String> localValues = ...;
Config config = Config.fromJson()
.load("config/application.json")
.add(localValues) // Overrides loaded properties
.build();
String host = config.get("host");
This configuration source supports watchable mutable configurations that can be persisted on files or output streams.
Example:
Map<String, String> localValues = ...;
FileWatchableConfig config = Config.fromJson()
.load("example/config.json")
.add(localValues) // Overrides loaded properties
.mutable()
.build();
config.set("host", "example.com");
config.remove("timeout");
Path path = ...;
config.save(path);
YAML
Jackson 2 based configuration instance that retrieves values from YAML files
or objects can be created using the Config.fromYaml() method.
Note: Requires Jackson 2.x com.fasterxml.jackson.dataformat:jackson-dataformat-yaml
dependency.
The library declares dependency as optional, so it must be included explicitly
in the project dependencies.
Example:
Map<String, String> localValues = ...;
Config config = Config.fromYaml()
.load("example/config.yml")
.add(localValues) // Overrides loaded properties
.build();
String host = config.get("host");
This configuration source supports watchable mutable configurations that can be persisted on files or output streams.
Example:
Map<String, String> localValues = ...;
FileWatchableConfig config = Config.fromYaml()
.load("example/config.yml")
.add(localValues) // Overrides loaded properties
.mutable()
.build();
config.set("host", "example.com");
config.remove("timeout");
Path path = ...;
config.save(path);
XML files
Configuration instance that retrieves values from XML files
or documents can be created using the Config.fromXml() method.
Note: This configuration source ignores root XML element when converting XML structure into configuration properties. When multiple files are loaded expects all files to share first loaded document's root XML element.
Example:
Map<String, String> localValues = ...;
Config config = Config.fromXml()
.load("example/config.xml")
.add(localValues) // Overrides loaded properties
.build();
String host = config.get("host");
This configuration source supports watchable mutable configurations that can be persisted on files or output streams.
Example:
Map<String, String> localValues = ...;
FileWatchableConfig config = Config.fromXml()
.load("example/config.xml")
.add(localValues) // Overrides loaded properties
.mutable()
.build();
config.set("host", "example.com");
config.remove("timeout");
Path path = ...;
config.save(path);
Spring environment
Configuration instance that retrieves values from Spring environment properties
can be created using the Config.fromSpringEnvironment() method.
Example:
Environment env = ...;
Config config = Config.fromSpringEnvironment()
.ofEnvironment(env)
.build();
String host = config.get("host");
By default Spring Environment does not allow iteration over properties keys,
but ConfigurableEnvironment does iterating over EnumerablePropertySource
properties, which is the most common scenario.
To enable iterable keys support, use the withIterableKeys() method:
ConfigurableEnvironment env = ...;
Config config = Config.fromSpringEnvironment()
.ofEnvironment(env)
.withIterableKeys()
.build();
if (config.contains("host")) {
String host = config.get("host");
}
This configuration source is read-only.
Java Preferences
Configuration instance that uses Java Preferences as storage mechanism
can be created using the Config.fromJavaPreferences() method.
Example:
String path = ...;
Config config = Config.fromJavaPreferences()
.ofUser(path)
.build();
String host = config.get("host");
This configuration source supports watchable mutable configurations that can be synchronized with persisted on files or output streams.
Example:
String path = ...;
PreferencesMutableConfig config = Config.fromJavaPreferences()
.ofUser(path)
.mutable()
.build();
config.set("host", "example.com");
config.remove("timeout");
// Synchronize changes to the underlying Preferences storage
config.sync();
// Flush changes to the persistent storage
config.flush();
Apache Commons Configuration
Configuration instance that delegates on Apache Commons
ImmutableConfiguration can be created using the
Config.fromApacheCommons() method.
Example:
ImmutableConfiguration delegated = ...;
Config config = Config.fromApacheCommons()
.ofDelegate(delegated)
.build();
String host = config.get("host");
This configuration source supports watchable mutable configurations delegated on .
Example:
Configuration delegated = ...;
WatchableConfig config = Config.fromApacheCommons()
.ofDelegate(delegated)
.mutable()
.build();
config.set("host", "example.com");
config.remove("timeout");
Shared options
Mutable configurations
When supported by the underlying configuration source, configuration
instances can be made mutable using the mutable() method,
allowing to set and remove configuration values.
Configuration hierarchy
A configuration can inherit values from a parent configuration declared
during the building process using the withParent() method.
This allows to create a hierarchy of configurations, where child configurations can inherit values from their parent configurations.
A tipical use case is to have a base configuration for the application, inhiriting environment variables and system properties, that can be extended by environment specific configurations, like development, testing and production configurations.
Example:
Config baseConfig = ConfigProvider.fromProperties()
.load("example/base.properties")
.withParent(Config.fromSystemProperties()
.withParent(Config.fromEnvironmentVariables()))
.build();
Config config = ConfigProvider.fromProperties()
.load("example/dev.properties")
.withParent(baseConfig)
.build();
Merging strategy
By default, when a configuration has a parent, the parent values have precedence over the child values. This means that if both configurations have a value for a given key, the parent configuration will provide the value for that key.
This behavior can be changed during the building process using the
withOverrideParentProperties() method. When this method is used, the child
configuration will have precedence over the parent configuration, meaning that
if both configurations have a value for a given key, the child configuration will
override the parent configuration and provide the value for that key.
Example:
Config baseConfig = ConfigProvider.fromProperties()
.load("example/base.properties")
.withParent(Config.fromSystemProperties()
.withParent(Config.fromEnvironmentVariables())
.build())
.build();
Config config = ConfigProvider.fromProperties()
.load("example/dev.properties")
.withParent(baseConfig)
.withOverrideParentProperties()
.build();
Decoders
Decoders allow decoding the configuration property values at runtime, by applying a transformation function to the values retrieved from the underlying configuration source.
This is useful for handling sensitive configuration values, like API keys or passwords, that should be stored in an encoded format in the configuration source, and decoded when retrieved for usage.
This is enabled using the withDecoder() method
during the building process, allowing to chain multiple decoders.
Example:
ValueDecoder parentDecode = ...;
Config parent = Config.fromProperties()
.add(Map.of(
"api.key", "my_encoded_api_key"))
.withDecoder(parentDecode)
.build();
ValueDecoder decode = ...;
Config config = Config.fromProperties()
.add(Map.of(
"api.child.key", "my_encoded_child_api_key"))
.withParent(parent)
.withDecoder(decode)
.build();
String apiKey = config.get("api.child.key");
// apiKey will be the result of decode("my_encoded_child_api_key")
String parentApiKey = config.get("api.key");
// parentApiKey will be the result of parentDecode("my_encoded_api_key")
Encoders
Encoders allow encoding the configuration property values at runtime, by applying a transformation function to the values set in the underlying configuration source.
This is useful for handling sensitive configuration values, like API keys or passwords, that should be stored in an encoded format in the configuration source, and encoded when set.
This is enabled using the withEncoder() method
during the building process, allowing to chain multiple encoders.
Example:
ValueEncoder parentEncode = ...;
MutableConfig parent = Config.fromProperties()
.mutable()
.withEncoder(parentEncode)
.build();
ValueEncoder encode = ...;
MutableConfig config = Config.fromProperties()
.withParent(parent)
.mutable()
.withEncoder(encode)
.build();
config.set("api.key", "my_plain_api_key");
// The value stored in the underlying configuration source of config
// will be the result encode("my_plain_api_key")
parent.set("api.key", "my_plain_api_key");
// The value stored in the underlying configuration source of parent
// will be the result of parentEncode("my_plain_api_key")
Cryptographic encoders and decoders
A special type of encoders and decoders are the cryptographic encoders and decoders, that allow to encode and decode configuration property values using cryptographic algorithms, like AES.
This is enabled using the withEncryption() methods during the building
process, passing a ConfigCryptoProvider instance that provides the
cryptographic transformations.
Example:
ConfigCryptoProvider crypto = ConfigCryptoProvider.builder()
.withAesGcmEngine("secretSalt".getBytes(StandardCharsets.UTF_8))
.withSecretKey("secretKey".toCharArray())
.build();
MutableConfig config = Config.fromProperties()
.add(Map.of(
"api.key", "my_encoded_api_key"))
.withEncryption(crypto)
.mutable()
.build();
String apiKey = config.get("api.key");
// apiKey will be the decrypted value of "my_encoded_api_key"
config.set("api.key", "my_plain_api_key");
// The value stored in the underlying configuration source of config
// will be the encrypted value of "my_plain_api_key"
Library provides built-in support for AES-GCM
algorithm. Additional algorithms can be implemented by providing custom
ConfigCryptoEngine implementations passed to
CryptoProviderEngineBuilder.withEngine():
ConfigCryptoEngine myCustomCryptoEngine = ...;
ConfigCryptoProvider crypto = ConfigCryptoProvider.builder()
.withEngine(myCustomCryptoEngine)
.withSecretKey("secretKey".toCharArray())
.build();
Cryptographic encoders can be used in read-only configurations as well, to decode encrypted configuration property values. Example:
ConfigCryptoProvider crypto = ...;
Config config = Config.fromProperties()
.add(Map.of(
"api.key", "my_encoded_api_key"))
.withEncryption(crypto)
.build();
String apiKey = config.get("api.key");
// apiKey will be the decrypted value of "my_encoded_api_key"
Cryptographic encoders and decoders can be chained with other encoders and decoders as well.
Example:
ConfigCryptoProvider crypto = ...;
ValueDecoder decode = ...;
ValueEncoder encode = ...;
MutableConfig config = Config.fromProperties()
.add(Map.of(
"api.key", "my_encoded_api_key"))
.withEncryption(crypto)
.withDecoder(decode)
.withEncoder(encode)
.mutable()
.build();
String apiKey = config.get("api.key");
// apiKey will be the result of decode(decrypted("my_encoded_api_key"))
config.set("api.key", "my_plain_api_key");
// The value stored in the underlying configuration source of config
// will be the encrypted(encode("my_plain_api_key"))
Decorators
Decorators allow modifying the configuration property values at runtime, by applying a transformation function to the values retrieved from the underlying configuration sources.
In oposition to decoders, decorators will modify only final values returned by the configuration instance, thus a decorator on the parent configuration will not affect the child configuration values, even if inherited from the parent.
This is enabled using the withDecorator() method
during the building process, allowing to chain multiple decorators.
Example:
ValueDecorator parentDecorate = ...;
Config parent = Config.fromProperties()
.add(Map.of(
"host", "example.com"))
.withDecorator(parentDecorate)
.build();;
ValueDecorator decorate = ...;
Config config = Config.fromProperties()
.withParent(parent)
.withDecorator(decorate)
.build();
String host = config.get("host");
// host will be the result of decorate("example.com")
String parentHost = parent.get("host");
// parentHost will be the result of parentDecorate("example.com")
Variable resolution
A special type of decorator is the variable resolution decorator,
that allows to use variables in configuration values, that will be
resolved with other configuration values at runtime.
This is enabled using the withVariableResolution() method
during the building process, allowing usage of multiple configuration
sources in the configuration hierarchy.
Example:
Config config = Config.fromProperties()
.add(Map.of(
"host", "example.com",
"port", "80"))
.withParent(Config.fromProperties()
.add(Map.of(
"service.url", "http://${host}:${port}/api",
"host", "localhost",
"port", "8080")))
.withOverrideParentProperties()
.withVariableResolution()
.build();
String url = config.get("service.url");
// url will be "http://example.com:80/api"
String parentUrl = config.getParent().get("service.url");
// parentUrl will be "http://${host}:${port}/api", as doesn't have variable resolution enabled
Variable substitutors can be chained with other decorators as well.
Example:
ValueDecorator decorate = value -> "decorated[" + value + "]";
Config config = Config.fromProperties()
.add(Map.of(
"service.url", "http://${host}:${port}/api",
"host", "localhost",
"port", "8080"))
.withVariableResolution()
.withDecorator(decorate)
.build();
String url = config.get("service.url");
// url will be "decorated[http://decorated[localhost]:decorated[8080]/api]"
