Mappings#
With SmallRye Config Mappings, it is possible to group multiple configuration properties in a single interface that share the same prefix (or namespace). It supports the following set of features:
- Automatic conversion of the configuration type, including
List,Set,Map,Optionaland primitive types. - Nested Config Mapping groups.
- Configuration Properties Naming Strategies
- Integration with Bean Validation
A Config Mapping requires an interface with minimal metadata configuration annotated with
io.smallrye.config.ConfigMapping:
The Server interface is able to map configurations with the name server.host into the Server#host() method and
server.port into Server#port() method. The configuration property name to lookup is built from the prefix, and the
method name with . (dot) as the separator.
Warning
If a mapping fails to match a configuration property a NoSuchElementException is thrown, unless the mapped
element is an Optional.
Registration#
Registration of Config Mappings is automatic in CDI aware environments with the @ConfigMapping annotation.
In non-CDI environments, the Config Mapping can be registered via SmallRyeConfigBuilder#withMapping. In this case,
the @ConfigMapping is completely optional (but recommendeded to set the prefix).
Retrieval#
A config mapping interface can be injected into any CDI aware bean:
@ApplicationScoped
class BusinessBean {
@Inject
Server server;
public void businessMethod() {
String host = server.host();
}
}
In non-CDI environments, use the API io.smallrye.config.SmallRyeConfig#getConfigMapping to retrieve the config
mapping instance:
SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class);
Server server = config.getConfigMapping(Server.class);
Info
Config Mapping instances are cached. They are populated when the Config instance is initialized and their values
are not updated on Config Source changes.
For a Config Mapping to be valid, it needs to match every configuration property name contained in the Config under
the specified prefix set in @ConfigMapping. This prevents unknown configuration properties in the Config. This
behaviour can be disabled with the configuration smallrye.config.mapping.validate-unknown=false.
Defaults#
The io.smallrye.config.WithDefault annotation allows to set a default property value into a mapping (and prevent
errors if the configuration value is not available in any ConfigSource).
No configuration properties are required. The Defaults#foo() will return the value foo and Defaults#bar() will
return the value bar.
Nested Groups#
A nested mapping provides a way to map sub-groups of configuration properties.
@ConfigMapping(prefix = "server")
public interface Server {
String host();
int port();
Log log();
interface Log {
boolean enabled();
String suffix();
boolean rotate();
}
}
server.host=localhost
server.port=8080
server.log.enabled=true
server.log.suffix=.log
server.log.rotate=false
The method name of a mapping group acts as a sub-prefix in the property name. In this case the matching property to
Server.Log#enabled is server.log.enabled.
Overriding property names#
@WithName#
If a method name and a property name do not match, the io.smallrye.config.WithName annotation can
override the method name mapping and use the name supplied in the annotation.
@WithParentName#
The io.smallrye.config.WithParentName annotation allows configurations mappings to inherit its parent container name,
simplifying the configuration property name required to match the mapping.
@ConfigMapping(prefix = "server")
interface Server {
@WithParentName
ServerHostAndPort hostAndPort();
@WithParentName
ServerInfo info();
}
interface ServerHostAndPort {
String host();
int port();
}
interface ServerInfo {
String name();
}
Without the @WithParentName the method ServerInfo#name maps the configuration property server.info.name. With
@WithParentName, the Server#info mapping will inherit the parent name from Server and ServerInfo#name maps to
the property server.name instead.
NamingStrategy#
Method names in camelCase map to kebab-case configuration property names by default.
The mapping strategy can be adjusted by setting namingStrategy value in the @ConfigMapping annotation.
@ConfigMapping(prefix = "server", namingStrategy = ConfigMapping.NamingStrategy.VERBATIM)
public interface ServerVerbatimNamingStrategy {
String theHost();
int thePort();
}
The @ConfigMapping annotation support the following naming stategies:
- KEBAB_CASE - The method name is derived by replacing case changes with a dash to map the configuration property.
- VERBATIM - The method name is used as is to map the configuration property.
- SNAKE_CASE - The method name is derived by replacing case changes with an underscore to map the configuration property.
Conversion#
A config mapping interface support automatic conversions of all types available for conversion in Config.
@ConfigMapping
public interface SomeTypes {
@WithName("int")
int intPrimitive();
@WithName("int")
Integer intWrapper();
@WithName("long")
long longPrimitive();
@WithName("long")
Long longWrapper();
@WithName("float")
float floatPrimitive();
@WithName("float")
Float floatWrapper();
@WithName("double")
double doublePrimitive();
@WithName("double")
Double doubleWrapper();
@WithName("char")
char charPrimitive();
@WithName("char")
Character charWrapper();
@WithName("boolean")
boolean booleanPrimitive();
@WithName("boolean")
Boolean booleanWrapper();
}
This is also valid for Optional and friends.
@ConfigMapping
public interface Optionals {
Optional<Server> server();
Optional<String> optional();
@WithName("optional.int")
OptionalInt optionalInt();
interface Server {
String host();
int port();
}
}
In this case, the mapping won’t fail if the configuraton properties values are missing.
@WithConverter#
The io.smallrye.config.WithConverter annotation provides a way to set a specific Converter in a mapping.
@ConfigMapping
public interface Converters {
@WithConverter(FooBarConverter.class)
String foo();
}
public static class FooBarConverter implements Converter<String> {
@Override
public String convert(final String value) {
return "bar";
}
}
A call to Converters.foo() results in the value bar.
Collections#
A config mapping is also able to map the collections types List and Set:
@ConfigMapping(prefix = "server")
public interface ServerCollections {
Set<Environment> environments();
interface Environment {
String name();
List<App> apps();
interface App {
String name();
List<String> services();
Optional<List<String>> databases();
}
}
}
server.environments[0].name=dev
server.environments[0].apps[0].name=rest
server.environments[0].apps[0].services=bookstore,registration
server.environments[0].apps[0].databases=pg,h2
server.environments[0].apps[1].name=batch
server.environments[0].apps[1].services=stock,warehouse
The List and Set mappings can use Indexed Properties to map configuration values in
mapping groups.
Maps#
A config mapping is also able to map a Map:
@ConfigMapping(prefix = "server")
public interface Server {
String host();
int port();
Map<String, String> form();
Map<String, List<Alias>> aliases();
interface Alias {
String name();
}
}
server.host=localhost
server.port=8080
server.form.index=index.html
server.form.login.page=login.html
server.form.error.page=error.html
server.aliases.localhost[0].name=prod
server.aliases.localhost[1].name=127.0.0.1
server.aliases.\"io.smallrye\"[0].name=smallrye
The configuration property name needs to specify an additional segment to act as the map key. The server.form matches
the Server#form Map and the segments index, login.page and error.page represent the Map
keys.
For collection types, the key requires the indexed format. The configuration name server.aliases.localhost[0].name
maps to the Map<String, List<Alias>> aliases() member, where localhost is the Map key, [0] is the index of the
List<Alias> collection where the Alias element will be stored, containing the name prod.
Info
They Map key part in the configuration property name may require quotes to delimit the key.
@WithUnnamedKey#
The io.smallrye.config.WithUnnamedKey annotation allows to omit a single map key in the configuration path:
@ConfigMapping(prefix = "server")
public interface Server {
@WithUnnamedKey("localhost")
Map<String, Alias> aliases();
interface Alias {
String name();
}
}
The sever.aliases.name is an unnamed Map property, because it does not contain the Map key to populate the Map
entry. Due to @WithUnnamedKey("localhost") the Map key is not required in the configuration path. The key used to
look up the Map entry is given by io.smallrye.config.WithUnnamedKey#value:
Server server = config.getConfigMapping(Server.class);
Map<String, Alias> localhost = server.aliases.get("localhost");
Warning
If the unnamed key (in this case localhost) is explicitly set in a property name, the mapping will throw an error.
@WithDefaults#
The io.smallrye.config.WithDefaults is a marker annotation to use only in a Map to return the default value for
the value element on any key lookup:
@ConfigMapping(prefix = "server")
public interface Server {
@WithDefaults
Map<String, Alias> aliases();
interface Alias {
@WithDefault("localhost")
String name();
}
}
A look up to the aliases Map with the key localhost, any or any other key, returns a Alias instance, where
Alias.name is localhost, because that is the default value. A look up to prod returns a Alias instance, where
Alias.name is prod because the property is defined in the configuration as server.aliases.prod.name=prod.
Server server = config.getConfigMapping(Server.class);
Map<String, Alias> localhost = server.aliases.get("localhost");
Map<String, Alias> any = server.aliases.get("any");
Map<String, Alias> any = server.aliases.get("prod");
ToString#
If the config mapping contains a toString method declaration, the config mapping instance will include a proper
implementation of the toString method.
Caution
Do not include a toString declaration in a config mapping with sensitive information.
Validation#
A config mapping may combine annotations from Bean Validation to validate configuration properties values.
@ConfigMapping(prefix = "server")
interface Server {
@Size(min = 2, max = 20)
String host();
@Max(10000)
int port();
}
The application startup fails with a io.smallrye.config.ConfigValidationException if the configuration properties
values do not follow the contraints defined in Server.
Info
For validation to work, the smallrye-config-validator dependency is required in the classpath.