An application can obtain its configuration programmatically via the ConfigProvider
.
In CDI enabled beans it can also get injected via @Inject Config
.
An application can then access its configured values via this Config
instance.
public class ConfigUsageSample {
public void useTheConfig() {
// get access to the Config instance
Config config = ConfigProvider.getConfig();
String serverUrl = config.getValue("acme.myprj.some.url", String.class);
callToServer(serverUrl);
// or
ConfigValue configServerUrl = config.getConfigValue("acme.myprj.some.url");
callToServer(configServerUrl.getValue());
}
}
If you need to access a different server then you can e.g. change the configuration via a Java -D
system property:
$> java -Dacme.myprj.some.url=http://other.server/other/endpoint -jar some.jar
Note that this is only one example how to possibly configure your application. Another example is to register Custom ConfigSources to e.g. pick up values from a database table, etc.
If a config value is a comma(,
) separated string, this value can be automatically converted to a multiple element array with \
as the escape character.
When specifying the property myPets=dog,cat,dog\\,cat
in a config source, the following code snippet can be used to obtain an array.
String[] myPets = config.getValue("myPets", String[].class); //myPets = {"dog", "cat", "dog,cat"}
MicroProfile Config also provides ways to inject configured values into your beans using the @Inject
and the @ConfigProperty
qualifier.
The @Inject
annotation declares an injection point. When using this on a passivation capable bean, refer to CDI Specification
for more details on how to make the injection point to be passivation capable.
@ApplicationScoped
public class InjectedConfigUsageSample {
@Inject
private Config config;
//The property myprj.some.url must exist with a non-empty value, otherwise a
//DeploymentException will be thrown.
@Inject
@ConfigProperty(name="myprj.some.url")
private String someUrl;
// You can also inject a configuration using the ConfigValue metadata object. The
// configured value will not lead to a DeploymentException if the value is missing.
// A default value can also be specified like any other configuration.
@Inject
@ConfigProperty(name="myprj.another.url")
private ConfigValue anotherUrl;
//The following code injects an Optional value of myprj.some.port property.
//Contrary to natively injecting the configured value, this will not lead to a
//DeploymentException if the value is missing.
@Inject
@ConfigProperty(name="myprj.some.port")
private Optional<Integer> somePort;
// You can also use the specialized Optional classes like OptionalInt,
// OptionalDouble, or OptionalLong to perform the injection. The configured value
// will not lead to a DeploymentException if the value is missing.
@Inject
@ConfigProperty(name="myprj.some.port")
private OptionalInt somePort;
//Injects a Provider for the value of myprj.some.dynamic.timeout property to
//resolve the property dynamically. Each invocation to Provider#get() will
//resolve the latest value from underlying Config.
//The existence of configured values will get checked during start-up.
//Instances of Provider<T> are guaranteed to be Serializable.
@Inject
@ConfigProperty(name="myprj.some.dynamic.timeout", defaultValue="100")
private jakarta.inject.Provider<Long> timeout;
//Injects a Supplier for the value of myprj.some.supplier.timeout property to
//resolve the property dynamically. Each invocation to Supplier#get() will
//resolve the latest value from underlying Config.
@Inject
@ConfigProperty(name="myprj.some.supplier.timeout", defaultValue="100")
private java.util.function.Supplier<Long> timeout;
//The following code injects an Array, List or Set for the `myPets` property,
//where its value is a comma separated value ( myPets=dog,cat,dog\\,cat)
@Inject @ConfigProperty(name="myPets") private String[] myArrayPets;
@Inject @ConfigProperty(name="myPets") private List<String> myListPets;
@Inject @ConfigProperty(name="myPets") private Set<String> mySetPets;
}
The table below defines the conversion rules, including some special edge case scenarios.
Input String | Output type | Method | behaviour |
---|---|---|---|
"foo,bar" |
String |
getValue |
"foo,bar" |
"foo,bar" |
String[] |
getValue |
{"foo", "bar"} |
"foo,bar" |
String |
getOptionalValue |
Optional.of("foo,bar") |
"foo,bar" |
String[] |
getOptionalValue |
Optional.of({"foo","bar"}) |
"foo,bar" |
String |
getOptionalValues |
Optional.of("foo", "bar") |
"foo," |
String |
getValue |
"foo," |
"foo," |
String[] |
getValue |
{"foo"} |
"foo," |
String |
getOptionalValue |
Optional.of("foo,") |
"foo," |
String[] |
getOptionalValue |
Optional.of({"foo"}) |
"foo," |
String |
getOptionalValues |
Optional.of("foo") |
",bar" |
String |
getValue |
",bar" |
",bar" |
String[] |
getValue |
{"bar"} |
",bar" |
String |
getOptionalValue |
Optional.of(",bar") |
",bar" |
String[] |
getOptionalValue |
Optional.of({"bar"}) |
",bar" |
String |
getOptionalValues |
Optional.of("bar") |
" " (space) |
String |
getValue |
" " |
" "(space) |
String[] |
getValue |
{" "} |
" "(space) |
String |
getOptionalValue |
Optional.of(" ") |
" "(space) |
String[] |
getOptionalValue |
Optional.of({" "}) |
" "(space) |
String |
getOptionalValues |
Optional.of(" ") |
missing |
String |
getValue |
throws |
missing |
String[] |
getValue |
throws |
missing |
String |
getOptionalValue |
Optional.empty() |
missing |
String[] |
getOptionalValue |
Optional.empty() |
missing |
String |
getOptionalValues |
Optional.empty() |
"" |
String |
getValue |
throws |
"" |
String[] |
getValue |
throws |
"" |
String |
getOptionalValue |
Optional.empty() |
"" |
String[] |
getOptionalValue |
Optional.empty() |
"" |
String |
getOptionalValues |
Optional.empty() |
"," |
String |
getValue |
"," |
"," |
String[] |
getValue |
throws |
"," |
String |
getOptionalValue |
Optional.of(",") |
"," |
String[] |
getOptionalValue |
Optional.empty() |
"," |
String |
getOptionalValues |
Optional.empty() |
"\," |
String |
getValue |
"\," |
"\," |
String[] |
getValue |
{","} |
"\," |
String |
getOptionalValue |
Optional.of("\,") |
"\," |
String[] |
getOptionalValue |
Optional.of({","}) |
"\," |
String |
getOptionalValues |
Optional.of(List.of(",")) |
",," |
String |
getValue |
",," |
",," |
String[] |
getValue |
throws |
",," |
String |
getOptionalValue |
Optional.of(",,") |
",," |
String[] |
getOptionalValue |
Optional.empty() |
",," |
String |
getOptionalValues |
Optional.empty() |
Sometimes, there is a need to remove a property. This can be done by setting an empty value or a value causing the corresponding converter returning null
in a config source.
When injecting a property that has been deleted, DeploymentException
will be thrown unless the return type is Optional
.
When injecting a number of related configuration properties, it can be tedious to repeat the statement of ConfigProperty
in scatter places.
Since they are related, it makes more sense to aggregate them into a single property class.
MicroProfile Config provides a way to look up a number of configuration properties starting with the same prefix using the @ConfigProperties
annotation, e.g. ConfigProperties(prefix="myPrefix")
.
When annotating a class with @ConfigProperties
or @ConfigProperties(prefix="myPrefix")
, any of its fields, regardless of the visibility, maps to a configuration property via the following mapping rules.
-
If the
prefix
is present, the fieldx
maps to the configuration property<prefix>.x
. -
If the
prefix
is absent, the fieldx
maps to the property namex
.
If the field name x
needs to be different from the config property name y
, use @ConfigProperty(name="y")
to perform the transformation.
If the prefix is present, the field x
maps to the configuration property <prefix>.y
, otherwise y
.
Considering the following config sources:
config_ordinal = 120
server.host = localhost
server.port=9080
server.endpoint=query
server.old.location=London
config_ordinal = 150
client.host = myHost
client.port=9081
client.endpoint=shelf
client.old.location=Dublin
host = anotherHost
port=9082
endpoint=book
old.location=Berlin
In order to retrieve the above properties in a single property class, you can use the @ConfigProperties
annotation with a prefix.
@ConfigProperties(prefix="server")
@Dependent
public class Details {
public String host; // the value of the configuration property server.host
public int port; // the value of the configuration property server.port
private String endpoint; //the value of the configuration property server.endpoint
public @ConfigProperty(name="old.location")
String location; //the value of the configuration property server.old.location
public String getEndpoint() {
return endpoint;
}
}
You can then use one of the following to retrieve the properties.
Since the class with @ConfigProperties
is a CDI bean, you can use the programmatic lookup provided by CDI, e.g.
Details details = CDI.current().select(Details.class, ConfigProperties.Literal.NO_PREFIX).get();
@Inject
@ConfigProperties
Details serverDetails;
The serverDetails
will contain the following info, as the prefix is server
:
serverDetails.host -> server.host -> localhost
serverDetails.port -> server.port -> 9080
serverDetails.endpoint -> server.endpoint -> query
serverDetails.getLocation() -> server.old.location -> London
Specify the prefix attribute on the annotation @ConfigProperties
when injecting the bean.
In this case, the prefix associated with @ConfigProperties
on this injection point overrides the prefix specified on the bean class.
@Inject
@ConfigProperties(prefix="client")
Details clientDetails;
The prefix client
overrides the prefix server
on the ServerDetails
bean. Therefore, this will retrieve the following properties.
clientDetails.host -> client.host -> myHost
clientDetails.port -> client.port -> 9081
clientDetails.endpoint -> client.endpoint -> shelf
clientDetails.getLocation() -> client.old.location -> Dublin
If @ConfigProperties
has no associated prefix at the injection point, it defaults to the prefix set in the Details
class, server
.
@Inject
@ConfigProperties
Details details;
Therefore, this will retrieve the following properties.
details.host -> server.host -> localhost
details.port -> server.port -> 9080
details.endpoint -> server.endpoint -> query
details.getLocation() -> server.old.location -> London
If @ConfigProperties
specifies an empty prefix at the injection point:
@Inject
@ConfigProperties(prefix = "")
Details details;
It overrides the prefix set on the bean class server
with an empty string ""
details.host -> host -> anotherHost
details.port -> port -> 9082
details.endpoint -> endpoint -> book
details.getLocation() -> old.location -> Berlin
The configuration properties class should contain a zero-arg constructor. Otherwise, the behaviour is unspecified.
When performing property lookup, a DeploymentException
will be thrown for the following scenarios:
-
The property is missing and neither default value nor the property return type is optional. Use one of the following to fix the problem.
-
Define a value for the property
-
Supply a default value when defining the field.
-
Use
@ConfigProperty
to provide a default value. -
Use
Optional<T>
orOptionalInt
,OptionalDouble
,OptionalLong
as the type.
-
-
The property value cannot be converted to the specified type
If any of the property cannot be found and there is neither default value nor property is not optional, java.util.NoSuchElementException
will be thrown.
In order to avoid this, you can supply a default value when defining the field. Alternatively, you can use @ConfigProperty
to provide a default value.
You can also use Optional<T>
or OptionalInt, OptionalDouble, OptionalLong as the type. If any property values cannot be converted to the specified type, java.lang.IllegalArgumentException
will be thrown.