Config.java
package dev.orne.config;
/*-
* #%L
* Orne Config
* %%
* Copyright (C) 2019 - 2025 Orne Developments
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.apache.commons.lang3.ObjectUtils;
import org.apiguardian.api.API;
import dev.orne.config.impl.CommonsConfigBuilderImpl;
import dev.orne.config.impl.ConfigSubtype;
import dev.orne.config.impl.ConfigSubset;
import dev.orne.config.impl.EnvironmentConfigBuilderImpl;
import dev.orne.config.impl.JsonConfigBuilderImpl;
import dev.orne.config.impl.PreferencesConfigBuilderImpl;
import dev.orne.config.impl.PropertiesConfigBuilderImpl;
import dev.orne.config.impl.SpringEnvironmentConfigBuilderImpl;
import dev.orne.config.impl.SystemConfigBuilderImpl;
import dev.orne.config.impl.XmlConfigBuilderImpl;
import dev.orne.config.impl.YamlConfigBuilderImpl;
/**
* Configuration properties provider.
*
* @author <a href="https://github.com/ihernaez">(w) Iker Hernaez</a>
* @version 1.0, 2019-07
* @version 2.0, 2025-05
* @since 0.1
*/
@API(status = API.Status.STABLE, since = "1.0")
public interface Config {
/**
* Creates a new environment variables based configuration builder.
*
* @return The configuration builder.
*/
static @NotNull EnvironmentConfigBuilder fromEnvironmentVariables() {
return new EnvironmentConfigBuilderImpl();
}
/**
* Creates a new system properties based configuration builder.
*
* @return The configuration builder.
*/
static @NotNull SystemConfigBuilder fromSystemProperties() {
return new SystemConfigBuilderImpl();
}
/**
* Creates a new {@code Properties} based configuration builder.
*
* @return The configuration builder.
*/
static @NotNull PropertiesConfigBuilder fromProperties() {
return new PropertiesConfigBuilderImpl();
}
/**
* Creates a new JSON based configuration builder.
*
* @return The configuration builder.
*/
static @NotNull JsonConfigBuilder fromJson() {
return new JsonConfigBuilderImpl();
}
/**
* Creates a new YAML based configuration builder.
*
* @return The configuration builder.
*/
static @NotNull YamlConfigBuilder fromYaml() {
return new YamlConfigBuilderImpl();
}
/**
* Creates a new XML based configuration builder.
*
* @return The configuration builder.
*/
static @NotNull XmlConfigBuilder fromXml() {
return new XmlConfigBuilderImpl();
}
/**
* Creates a new {@code Preferences} based configuration builder.
*
* @return The configuration builder.
*/
static @NotNull PreferencesConfigInitialBuilder fromJavaPreferences() {
return new PreferencesConfigBuilderImpl();
}
/**
* Creates a new Apache Commons Configuration based configuration
* builder.
*
* @return The configuration builder.
*/
static @NotNull CommonsConfigBuilder fromApacheCommons() {
return new CommonsConfigBuilderImpl();
}
/**
* Creates a new Spring Environment based configuration
* builder.
*
* @return The configuration builder.
*/
static @NotNull SpringEnvironmentConfigInitialBuilder fromSpringEnvironment() {
return new SpringEnvironmentConfigBuilderImpl();
}
/**
* Creates a configuration proxy of the specified type.
* <p>
* The configuration proxy will delegate all method calls to the
* underlying configuration instance, except for the default methods
* defined in the specified type interface, which will be invoked directly
* on the interface.
*
* @param <T> The configuration type.
* @param config The proxied configuration instance.
* @param type The configuration type interface to create a proxy for.
* @return The proxy of the specified configuration type.
*/
static <T extends Config> T as(
final @NotNull Config config,
final @NotNull Class<T> type) {
if (type.isInstance(config)) {
return type.cast(config);
} else {
return ConfigSubtype.create(config, type);
}
}
/**
* Returns the parent configuration, if any.
*
* @return The parent configuration
*/
default Config getParent() {
return null;
}
/**
* Returns {@code true} if the configuration contains no property.
*
* @return Returns {@code true} if the configuration contains no property.
* @throws NonIterableConfigException If the configuration property keys
* cannot be iterated.
* @throws ConfigException If an error occurs accessing the configuration.
*/
default boolean isEmpty() {
return !getKeys().iterator().hasNext();
}
/**
* Returns {@code true} if the property with the key passed as argument
* has been configured.
*
* @param key The configuration property.
* @return Returns {@code true} if the property has been configured.
*/
default boolean contains(
@NotBlank String key) {
return get(key) != null;
}
/**
* Returns the configuration property keys contained in this configuration.
*
* @return The configuration property keys.
* @throws NonIterableConfigException If the configuration property keys
* cannot be iterated.
* @throws ConfigException If an error occurs accessing the configuration.
*/
default @NotNull Stream<String> getKeys() {
throw new NonIterableConfigException(
"Configuration property keys cannot be iterated.");
}
/**
* Returns the configuration property keys contained in this configuration
* that match the specified predicate.
*
* @param filter The predicate to filter the property keys with.
* @return The configuration property keys that match the predicate.
* @throws NonIterableConfigException If the configuration property keys
* cannot be iterated.
* @throws ConfigException If an error occurs accessing the configuration.
*/
default @NotNull Stream<String> getKeys(
final @NotNull Predicate<String> filter) {
return getKeys().filter(filter);
}
/**
* Returns the configuration property keys contained in this configuration
* that start with the specified prefix.
*
* @param prefix The predicate to filter the property keys with.
* @return The configuration property keys that match the predicate.
* @throws NonIterableConfigException If the configuration property keys
* cannot be iterated.
* @throws ConfigException If an error occurs accessing the configuration.
*/
default @NotNull Stream<String> getKeys(
final @NotNull String prefix) {
return getKeys(key -> key.startsWith(prefix));
}
/**
* Returns the value of the configuration parameter as {@code String}.
*
* @param key The configuration property
* @return The configuration parameter value as {@code String}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
String get(
@NotBlank String key);
/**
* Returns the value of the configuration parameter as {@code String}
* without applying any decoration or transformation.
*
* @param key The configuration property
* @return The configuration parameter value as {@code String}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default String getUndecored(
@NotBlank String key) {
return get(key);
}
/**
* Returns the value of the configuration parameter as {@code String}.
*
* @param key The key of the configuration parameter
* @param defaultValue The default value to return if the configuration
* parameter is not set or is {@code null}.
* @return The configuration parameter value as {@code String}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default String get(
@NotBlank String key,
String defaultValue) {
return ObjectUtils.firstNonNull(get(key), defaultValue);
}
/**
* Returns the value of the configuration parameter as {@code String}.
*
* @param key The key of the configuration parameter
* @param defaultValue The default value supplier if the configuration
* parameter is not set or is {@code null}.
* @return The configuration parameter value as {@code String}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default String get(
@NotBlank String key,
@NotNull Supplier<String> defaultValue) {
return ObjectUtils.getFirstNonNull(() -> get(key), defaultValue);
}
/**
* Returns the value of the configuration parameter as {@code Boolean}.
*
* @param key The key of the configuration parameter
* @return The configuration parameter value as {@code Boolean}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default Boolean getBoolean(
@NotBlank String key) {
final String value = get(key);
return value == null ? null : Boolean.parseBoolean(value);
}
/**
* Returns the value of the configuration parameter as {@code Boolean}.
*
* @param key The key of the configuration parameter
* @param defaultValue The default value to return if the configuration
* parameter is not set or is {@code null}.
* @return The configuration parameter value as {@code Boolean}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default boolean getBoolean(
@NotBlank String key,
boolean defaultValue) {
return ObjectUtils.firstNonNull(getBoolean(key), defaultValue);
}
/**
* Returns the value of the configuration parameter as {@code Boolean}.
*
* @param key The key of the configuration parameter
* @param defaultValue The default value supplier if the configuration
* parameter is not set or is {@code null}.
* @return The configuration parameter value as {@code Boolean}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default Boolean getBoolean(
@NotBlank String key,
@NotNull Supplier<Boolean> defaultValue) {
return ObjectUtils.getFirstNonNull(() -> getBoolean(key), defaultValue);
}
/**
* Returns the integer value of the specified configuration property,
* with variable substitution.
*
* @param key The configuration property.
* @return The value configuration property, if any.
* @throws NumberFormatException If the configuration value cannot be
* parsed as an integer.
*/
default Integer getInteger(
@NotNull String key) {
final String strValue = get(key);
return strValue == null ? null : Integer.valueOf(strValue);
}
/**
* Returns the integer value of the specified configuration property,
* with variable substitution.
*
* @param key The configuration property.
* @param defaultValue The default value to return if the configuration
* parameter is not set or is {@code null}.
* @return The value configuration property, if any.
* @throws NumberFormatException If the configuration value cannot be
* parsed as an integer.
*/
default int getInteger(
@NotNull String key,
int defaultValue) {
return Integer.parseInt(get(key, String.valueOf(defaultValue)));
}
/**
* Returns the value of the configuration parameter as {@code Boolean}.
*
* @param key The key of the configuration parameter
* @param defaultValue The default value supplier if the configuration
* parameter is not set or is {@code null}.
* @return The configuration parameter value as {@code Boolean}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default Integer getInteger(
@NotBlank String key,
@NotNull Supplier<Integer> defaultValue) {
return ObjectUtils.getFirstNonNull(() -> getInteger(key), defaultValue);
}
/**
* Returns the integer value of the specified configuration property,
* with variable substitution.
*
* @param key The configuration property.
* @return The value configuration property, if any.
* @throws NumberFormatException If the configuration value cannot be
* parsed as an long.
*/
default Long getLong(
@NotNull String key) {
final String strValue = get(key);
return strValue == null ? null : Long.valueOf(strValue);
}
/**
* Returns the integer value of the specified configuration property,
* with variable substitution.
*
* @param key The configuration property.
* @param defaultValue The default value to return if the configuration
* parameter is not set or is {@code null}.
* @return The value configuration property, if any.
* @throws NumberFormatException If the configuration value cannot be
* parsed as an long.
*/
default long getLong(
@NotNull String key,
long defaultValue) {
return Long.parseLong(get(key, String.valueOf(defaultValue)));
}
/**
* Returns the value of the configuration parameter as {@code Boolean}.
*
* @param key The key of the configuration parameter
* @param defaultValue The default value supplier if the configuration
* parameter is not set or is {@code null}.
* @return The configuration parameter value as {@code Boolean}
* @throws ConfigException If an error occurs retrieving the configuration
* property value
*/
default Long getLong(
@NotBlank String key,
@NotNull Supplier<Long> defaultValue) {
return ObjectUtils.getFirstNonNull(() -> getLong(key), defaultValue);
}
/**
* Creates a configuration proxy of the specified type.
* <p>
* The configuration proxy will delegate all method calls to this
* configuration instance, except for the default methods
* defined in the specified type interface, which will be invoked directly
* on the interface.
*
* @param <T> The configuration type.
* @param type The configuration type interface to create a proxy for.
* @return The proxy of the specified configuration type.
* @see #as(Config, Class)
*/
default <T extends Config> T as(
final @NotNull Class<T> type) {
return Config.as(this, type);
}
/**
* Creates a subset configuration containing only the properties
* with the specified prefix.
*
* @param prefix The prefix for configuration keys.
* @return The subset configuration.
*/
default @NotNull Config subset(
final @NotNull String prefix) {
return ConfigSubset.create(this, prefix);
}
}