Chapter 4. Configuration
In this chapter, you’ll learn the following about setting configuration parameters:
-
How to configure a Quarkus service
-
How to inject configuration parameters in the service
-
How to apply values depending on the environment
-
How to correctly configure the logging system
-
How to create customizations for the configuration system
4.1 Configuring the Application with Custom Properties
Solution
Quarkus makes use of a number of the Eclipse MicroProfile specifications. One of those is the Configuration specification; however, to simplify configuration, Quarkus uses just one file for all configurations, application.properties, which must be placed in the root of the classpath.
This file can be used to configure Quarkus properties such as logging or default path, Quarkus extensions like data source or Kafka, or custom properties that you define for the application. You are going to see all of them in the book, but in this recipe, you’ll see the latter one.
Open the src/main/resources/application.properties file and add the following property:
greeting.message
=
Hello World
You can inject the property value defined in application.properties by using the org.eclipse.microprofile.config.inject.ConfigProperty
annotation in a field.
Open org.acme.quickstart.GreetingResource.java
and inject greeting.message
property value:
@ConfigProperty
(
name
=
"greeting.message"
)
String
message
;
@GET
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
hello
(
)
{
return
message
;
}
Injects the value of
greeting.message
propertyPlaces fields in package-protected scope
Returns the configured value
Tip
For performance reasons when using GraalVM and reflection, we encourage you to use protected-package scope on fields that will be injected at runtime. You can read more about it in the Quarkus CDI Reference Guide.
In a new terminal window, make a request to /hello
to see that the output message is the configured value in application.properties:
curl http://localhost:8080/hello
Hello World
If you want to make a configuration field not mandatory and provide a default value, you can use the defaultValue
attribute of @ConfigProperty
annotation.
Open the org.acme.quickstart.GreetingResource.java
file and inject the greeting.upper-case
property value:
@ConfigProperty
(
name
=
"greeting.upper-case"
,
defaultValue
=
"true"
)
boolean
upperCase
;
@GET
@Path
(
"/optional"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
helloOptional
(
)
{
return
upperCase
?
message
.
toUpperCase
(
)
:
message
;
}
And in a terminal window, make a request to /hello/optional
to see that the output message is in upper case:
curl http://localhost:8080/hello/optional
HELLO WORLD
Multivalue properties are supported—you need to define only the field type as one of Arrays
, java.util.List
or java.util.Set
, depending on your requirements/preference.
The delimiter for the property value is a comma (,
) and the escape character is the backslash (\
).
Open the src/main/resources/application.properties file and add the following property with three values:
greeting.suffix
=
!!, How are you???
Open org.acme.quickstart.GreetingResource.java and inject greeting.suffix
property values:
@ConfigProperty
(
name
=
"greeting.suffix"
)
List
<
String
>
suffixes
;
@GET
@Path
(
"/list"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
helloList
()
{
return
message
+
suffixes
.
get
(
1
);
}
And in a terminal window make a request to /hello/list
to see that the output message contains the second suffix:
curl http://localhost:8080/hello/list
Hello World How are you?
The YAML format is also supported for configuring the application. In this case, the file is named application.yaml or application.yml.
To start using the YAML configuration file, you need to add the config-yaml
extension:
./mvnw quarkus:add-extension -Dextensions="config-yaml"
Given the following configuration file using the properties
format:
greeting.message
=
Hello World
%staging.quarkus.http.port
=
8182
quarkus.http.cors
=
true
quarkus.http.cors.methods
=
GET,PUT,POST
The equivalent in YAML format follows:
greeting
:
message
:
Hello
World
"
%staging
"
:
quarkus
:
http
:
port
:
8182
quarkus
:
http
:
cors
:
~
:
true
methods
:
GET,PUT,POST
Discussion
Eclipse MicroProfile Configuration comes with the following built-in converters to map a configuration value into a Java object:
-
boolean
andjava.lang.Boolean
; the values for true aretrue
,1
,YES
,Y
, andON
, while any other value is consideredfalse
-
byte
andjava.lang.Byte
-
short
andjava.lang.Short
-
int
andjava.lang.Integer
-
long
andjava.lang.Long
-
float
andjava.lang.Float
-
double
andjava.lang.Double
-
char
andjava.lang.Character
-
java.lang.Class
based on the result of the call ofClass.forName
If a built-in converter or custom converter does not exist, then the following methods are checked in the target object. If a built-in converter or custom converter does exist, the discovered/found method is used to instantiate the converter object and the string argument is passed for conversion:
-
Target type has
public static T of(String)
method -
Target type has
public static T valueOf(String)
method -
Target type has public constructor with a
String
parameter -
Target type has
public static T parse(CharSequence)
method
4.2 Accessing Configuration Properties Programmatically
Solution
Inject the org.eclipse.microprofile.config.Config
class in the object for which you want to access properties programmatically.
The Eclipse MicroProfile Configuration spec allows you to inject org.eclipse.microprofile.config.Config
to get properties programmatically instead of injecting directly with ConfigProperty
.
Open org.acme.quickstart.GreetingResource.java
and inject Config
class:
@Inject
Config
config
;
@GET
@Path
(
"/config"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
helloConfig
(
)
{
config
.
getPropertyNames
(
)
.
forEach
(
p
-
>
System
.
out
.
println
(
p
)
)
;
return
config
.
getValue
(
"greeting.message"
,
String
.
class
)
;
}
Use
Inject
CDI annotation to inject the instanceYou can now access the list of properties
Property needs to be cast to final type
You can access the Config
class without using CDI by calling ConfigProvider.getConfig()
method.
4.3 Overwriting Configuration Values Externally
Solution
You can overwrite any property at runtime by setting it as a system property or environment variable.
Quarkus lets you overwrite any configuration property by setting a configuration
as a system property (-Dproperty.name=value
) and/or as an environment variable (export PROPERTY_NAME=value
).
System properties have more priority than environment variables.
Examples of externalizing these properties can be a database URL, username, or password because they are known only in the target environment. But you need to know that there is a trade-off because the more runtime properties are available, the less build time prework Quarkus can do.
Let’s package the application used in Recipe 4.1 and override the greeting.message
property by setting a system property:
./mvnw clean package -DskipTests
java -Dgreeting.message=Aloha -jar target/getting-started-1.0-SNAPSHOT-runner.jar
In a new terminal window, validate that the property has been overridden from Hello World
to Aloha
by running:
curl localhost:8080/hello
Aloha
In the case of environment variables, three naming conventions for a given property name are supported.
This is because some operating systems allow only alphabetic characters and underscores (_
) but no other characters, like dots (.
).
To support all possible cases, the following rules are used:
-
Exactly match (
greeting.message
). -
Replace nonalphanumeric characters to underscore (
greeting_message
). -
Replace nonalphanumeric characters to underscore and convert the rest to upper case (
GREETING_MESSAGE
).
Here is the application.properties file:
greeting.message
=
Hello World
You can override its value using any of the following environment variable names because all of them are equivalent:
export greeting.message=Aloha
export greeting_message=Aloha
export GREETING_MESSAGE=Aloha
There is also a special place where you can put the application.properties file outside the application itself, inside a directory named config where the application runs. Any runtime properties defined in that file will override the default configuration.
Important
config/application.properties works in development mode as well, but you need to add it on your build tool output directory to make it work (in case of the Maven, the target directory; in case of Gradle, build), so you need to be aware of the need to re-create it when running the clean
task.
Apart from environment variables and the application.properties file, you can also place a .env file in the current working directory to override configuration values,
following the environment variables format (GREETING_MESSAGE=Aloha
).
4.4 Configuring with Profiles
Solution
Quarkus supports the notion of configuration profiles. These allow you to have multiple configuration values for the same property in the same file and enable different values to suit the environment in which you are running the service.
The syntax for configuration profiles is %{profile}.config.key=value
.
Discuss
Quarkus comes with three built-in profiles.
- dev
-
Activated when in development mode (i.e.,
quarkus:dev
). - test
-
Activated when running tests.
- prod
-
The default profile when not running in development or test mode; you don’t need to set it in application.properties, as it is implicitly set.
Open src/main/resources/application.properties file and set to start Quarkus at port 8181 in development mode:
%dev.quarkus.http.port
=
8181
After this change, start the service to again check that the listening port is 8181 instead of the default one (8080):
./mvnw compile quarkus:dev
INFO [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
INFO [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed
in 671ms
INFO [io.quarkus] (main) Quarkus 1.4.1 started in 1.385s. Listening on:
http://0.0.0.0:8181
INFO [io.quarkus] (main) Profile dev activated. Live Coding activated.
INFO [io.quarkus] (main) Installed features:
[cdi, hibernate-validator, resteasy]
Notice that now the listening address is http://0.0.0.0:8181 instead of the default one.
Finally, rollback to 8080 port, remove %dev.quarkus.http.port=8181
line in application.properties to align with the port that is used in the rest of the book.
4.5 Changing Logger Configuration
Solution
Quarkus uses a unified configuration model in which all configuration properties are placed in the same file. In the case of Quarkus, this file is application.properties, and you can configure many aspects of logging there.
For example, if you want to change the logging level, you just set quarkus.log.level
to the minimum log level.
Open src/main/resources/application.properties and add the following content:
quarkus.log.level
=
DEBUG
Now start the application to see that a lot of new logging messages are printed in the console:
./mvnw compile quarkus:dev
...
[INFO] --- quarkus-maven-plugin:0.22.0:dev (default-cli) @ getting-started ---
Listening for transport dt_socket at address: 5005
DEBUG [org.jbo.logging] (main) Logging Provider: \
org.jboss.logging.JBossLogManagerProvider
INFO [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
DEBUG [io.qua.run.con.ConverterSupport] (main) Populate SmallRye config builder
with converter for class java.net.InetSocketAddress of priority 200
DEBUG [io.qua.run.con.ConverterSupport] (main) Populate SmallRye config builder
with converter for class org.wildfly.common.net.CidrAddress of priority 200
Note
We had to span multiple lines for formatting in the book; we have used the backslash to indicate this.
You can also enable storing logs in a file by using quarkus.log.file.enable
property.
The output is written by default to a file named quarkus.log:
quarkus.log.file.enable
=
true
Note
While you are in development and working out of the source directory, your logging file will be in target directory.
4.6 Adding Application Logs
Solution
Most of the time, your applications need to write their own logging messages and not rely solely on the default logs provided by Quarkus. Applications may use any of the supported APIs for logging, and the logs will be merged.
Quarkus supports these logging libraries:
-
JDK java.util.logging
-
JBoss logging
-
SLF4J
-
Apache Commons Logging
Let’s see how to use JBoss Logging
to log content.
Open org.acme.quickstart.GreetingResource.java
and log a message when an special endpoint is called:
private
static
org
.
jboss
.
logging
.
Logger
logger
=
org
.
jboss
.
logging
.
Logger
.
getLogger
(
GreetingResource
.
class
)
;
@GET
@Path
(
"/log"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
helloLog
(
)
{
logger
.
info
(
"I said Hello"
)
;
return
"hello"
;
}
Now start the application:
./mvnw compile quarkus:dev
In a new terminal, window make a request to /hello/log
:
curl http://localhost:8080/hello/log
If you inspect the terminal where you started Quarkus, you’ll see the next logline:
INFO [org.acm.qui.GreetingResource] (executor-thread-1) I said Hello
Discussion
Logging is done on a per-category basis. A configuration that applies to a category also applies to all subcategories of that category, unless there is a more specific matching subcategory configuration.
Categories are represented by class location (i.e., the package, or subpackages,
where they are defined).
For example, if you want to set Undertow security logging
to trace level, you need to set the
quarkus.log.category."io.undertow.request.security".level=TRACE
property in application.properties.
Following the previous example, let’s restrict log lines from classes residing in org.acme.quickstart
(and subclasses) so the minimum log level is WARNING
:
quarkus.log.category."org.acme.quickstart".level
=
WARNING
If you repeat the request to http://localhost:8080/hello/log, logline is no longer written down.
4.7 Advanced Logging
Solution
When working with microservice architectures and Kubernetes, logging is an important thing to take into consideration because each service is logging individually; but as a developer or operator, you might want to have all the logs centralized in one place so they can be consumed as a whole.
Quarkus logging also supports JSON and GELF output.
These logs can be written in JSON format instead of plain text for machine processing by registering the logging-json
extension:
./mvnw quarkus:add-extension -Dextensions="logging-json"
Use the GELF extension to produce logs in GELF format and send them using either TCP or UDP.
Graylog extended log format (GELF) is understood by three of the most centralized logs systems that are used nowadays:
-
Graylog (MongoDB, Elasticsearch, Graylog)
-
ELK (Elasticsearch, Logstash, Kibana)
-
EFK (Elasticsearch, Fluentd, Kibana)
To start logging in GELF format, all you need to do is add the logging-gelf
extension:
./mvnw quarkus:add-extension -Dextensions="logging-gelf"
Logging code is not changing, so the same interfaces are used:
private
static
org
.
jboss
.
logging
.
Logger
logger
=
org
.
jboss
.
logging
.
Logger
.
getLogger
(
GreetingResource
.
class
)
;
@GET
@Path
(
"/log"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
helloLog
(
)
{
logger
.
info
(
"I said Hello"
)
;
return
"hello"
;
}
The GELF handler must be configured in application.properties:
quarkus.log.handler.gelf.enabled
=
true
quarkus.log.handler.gelf.host
=
localhost
quarkus.log.handler.gelf.port
=
12201
Important
If you are using Logstash (ELK), you need to enable the Input plug-in that understands the GELF format:
input { gelf { port => 12201 } } output { stdout {} elasticsearch { hosts => ["http://elasticsearch:9200"] } }
Important
If you are using Fluentd (EFK), you need to enable the Input plug-in that understands the GELF format:
<source> type gelf tag example.gelf bind 0.0.0.0 port 12201 </source> <match example.gelf> @type elasticsearch host elasticsearch port 9200 logstash_format true </match>
Discussion
Quarkus logging also supports syslog format by default without the requirement of adding any extension. Syslog format can be used in Fluentd as an alternative to GELF format in Quarkus:
quarkus.log.syslog.enable
=
true
quarkus.log.syslog.endpoint
=
localhost:5140
quarkus.log.syslog.protocol
=
udp
quarkus.log.syslog.app-name
=
quarkus
quarkus.log.syslog.hostname
=
quarkus-test
Important
You need to enable the Input plug-in that understands the syslog format in Fluentd:
<source> @type syslog port 5140 bind 0.0.0.0 message_format rfc5424 tag system </source> <match **> @type elasticsearch host elasticsearch port 9200 logstash_format true </match>
If you are using Kubernetes, the simplest way to log is to log to the console and install into the cluster a central log manager that collects all log lines.
4.8 Configuring with Custom Profiles
Solution
So far, you’ve seen that Quarkus comes with built-in profiles so that you can set different configuration values for the same property and enable them to suit the environment. But with Quarkus, you can also set your own profiles.
The only thing you need to do is specify which profile you want to enable by either using the quarkus.profile
system property or the QUARKUS_PROFILE
environment variable.
If both are set, the system property takes precedence over the environment
variable.
Then the only thing you need to do is create the property with the profile name and set the current profile to that name. Let’s create a new staging profile that overwrites the listening port of Quarkus.
Open src/main/resources/application.properties file and set to start Quarkus at port 8182 when the staging
profile is enabled:
%staging.quarkus.http.port
=
8182
Then start the application with staging
profile enabled:
./mvnw -Dquarkus.profile=staging compile quarkus:dev
INFO [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
INFO [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed
in 640ms
INFO [io.quarkus] (main) Quarkus 0.23.2 started in 1.300s. Listening on:
http://0.0.0.0:8182
INFO [io.quarkus] (main) Profile staging activated. Live Coding activated.
INFO [io.quarkus] (main) Installed features: [cdi, hibernate-validator,
resteasy]
In this case, the system property approach is used, but you could also set it using the QUARKUS_PROFILE
environment variable.
Discussion
If you want to set the running profile in tests, you only need to set the quarkus.test.profile
system property to the given profile in your build script—for example, in Maven:
<groupId>
org.apache.maven.plugins</groupId>
<artifactId>
maven-surefire-plugin</artifactId>
<version>
${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<quarkus.test.profile>
foo</quarkus.test.profile>
<buildDirectory>
${project.build.directory}</buildDirectory>
</systemPropertyVariables>
</configuration>
or, in Gradle:
test
{
useJUnitPlatform
()
systemProperty
"quarkus.test.profile"
,
"foo"
}
Also, you can change the default production profile.
The built-in profile in Quarkus is prod
, so when you are running your application without any profile, this is the default one where the values are taken.
But you can change that at build time so that, without specifying any profile, your profile is the default one when the application is running.
The only thing you need to do is build the application using the quarkus.profile
system property with the profile value you want set as the default:
./mvnw package -Pnative -Dquarkus.profile=prod-kubernetes`
./target/getting-started-1.0-runner
4.9 Creating Custom Sources
Solution
Quarkus uses the Eclipse MicroProfile Configuration spec to implement all the logic regarding configuration.
The specification offers
org.eclipse.microprofile.config.spi.ConfigSource
Java SPI interface to implement a
custom way to load configuration properties instead of/apart from the default one
provided by Quarkus.
For example, you could load configuration properties from a database, an XML file, or a REST API.
Let’s create a simple in-memory config source that gets configuration properties from Map
populated at instantiation time.
Create a new class called org.acme.quickstart.InMemoryConfigSource.java
:
package
org
.
acme
.
quickstart
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.eclipse.microprofile.config.spi.ConfigSource
;
public
class
InMemoryConfigSource
implements
ConfigSource
{
private
Map
<
String
,
String
>
prop
=
new
HashMap
<
>
(
)
;
public
InMemoryConfigSource
(
)
{
prop
.
put
(
"greeting.color"
,
"red"
)
;
}
@Override
public
int
getOrdinal
(
)
{
return
500
;
}
@Override
public
Map
<
String
,
String
>
getProperties
(
)
{
return
prop
;
}
@Override
public
String
getValue
(
String
propertyName
)
{
return
prop
.
get
(
propertyName
)
;
}
@Override
public
String
getName
(
)
{
return
"MemoryConfigSource"
;
}
}
Populates map with a property
Used to determine the importance of the values; the highest ordinal takes precedence over the lower-priority ordinal
Gets all properties as
Map
; in this case it is directGets the value for a single property
Returns the name of this config source
Then you need to register this as a Java SPI. Create the services folder at src/main/resources/META-INF. Next, create a file inside services named org.eclipse.microprofile.config.spi.ConfigSource with the following content:
org.acme.quickstart.InMemoryConfigSource
Finally, you can modify the org.acme.quickstart.GreetingResource.java
class to inject this property:
@ConfigProperty
(
name
=
"greeting.color"
)
String
color
;
@GET
@Path
(
"/color"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
color
(
)
{
return
color
;
}
And in a terminal window make a request to /hello/color
to see that the output message is the configured value in the custom source:
curl http://localhost:8080/hello/color
red
Discussion
Each ConfigSource
has a specified ordinal, which is used to set the importance of the values taken from the ConfigSource
in the case of multiple config sources defined for the same application.
A higher ordinal ConfigSource
is used over a ConfigSource
with a lower value.
Using the defaults in the following list as a reference, a system property will be used over everything, and the application.properties file in the src/main/resources directory will be used if no other ConfigSources
are found:
-
System properties to 400
-
Environment variables to 300
-
application.properties at config directory to 260
-
application.properties at project to 250
4.10 Creating Custom Converters
Solution
You can convert a property from String
to any kind of object by implementing the org.eclipse.microprofile.config.spi.Converter
Java SPI.
Quarkus uses the Eclipse MicroProfile Configuration spec to implement all the logic regarding configuration.
The specification offers the org.eclipse.microprofile.config.spi.Converter
Java SPI interface to implement the conversion of configuration values to a custom type.
For example, you could transform a percentage value (i.e., 15%) to a Percentage
type, wrapping the percentage as double
type.
Create a new POJO class org.acme.quickstart.Percentage.java
:
package
org
.
acme
.
quickstart
;
public
class
Percentage
{
private
double
percentage
;
public
Percentage
(
double
percentage
)
{
this
.
percentage
=
percentage
;
}
public
double
getPercentage
()
{
return
percentage
;
}
}
And then create a class org.acme.quickstart.PercentageConverter.java
that converts from String
representation to Percentage
:
package
org
.
acme
.
quickstart
;
import
javax.annotation.Priority
;
import
org.eclipse.microprofile.config.spi.Converter
;
@Priority
(
300
)
public
class
PercentageConverter
implements
Converter
<
Percentage
>
{
@Override
public
Percentage
convert
(
String
value
)
{
String
numeric
=
value
.
substring
(
0
,
value
.
length
(
)
-
1
)
;
return
new
Percentage
(
Double
.
parseDouble
(
numeric
)
/
100
)
;
}
}
Sets the priority; in this specific case it might be optional
Generic type that sets the type to convert to
Then you need to register this as a Java SPI. Create the services folder at src/main/resources/META-INF. Next, create a file inside the services folder named org.eclipse.microprofile.config.spi.Converter with the following content:
org.acme.quickstart.PercentageConverter
Then, you can modify the org.acme.quickstart.GreetingResource.java
class to inject this property:
@ConfigProperty
(
name
=
"greeting.vat"
)
Percentage
vat
;
@GET
@Path
(
"/vat"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
vat
()
{
return
Double
.
toString
(
vat
.
getPercentage
());
}
Lastly, you will need to add a new property into the application.properties file in your src/main/resources directory:
greeting.vat
=
21%
And in a terminal window, make a request to /hello/vat
to see that the output message is the transformed vat as double:
curl http://localhost:8080/hello/vat
0.21
Discussion
By default, if no @Priority
annotation can be found on a converter, it is registered with a priority of 100.
Quarkus converters are registered with a priority of 200, so if you want to replace a Quarkus converter, you should use a higher value; if you don’t need to replace a Quarkus converter, then the default one is perfectly fine.
A list of Quarkus core converters has been shown in Recipe 4.1.
4.11 Grouping Configuration Values
Solution
You can group common properties (those with the same prefix) using the @io.quarkus.arc.config.ConfigProperties
annotation.
When you are creating ad hoc configuration properties in your application, typically these properties will have the same prefix (i.e., greetings
).
To inject all these properties, you can use the @ConfigProperty
annotation (as shown in Recipe 4.1), or
you can use the io.quarkus.arc.config.ConfigProperties
annotation to group
properties together.
Using the application.properties file:
greeting.message
=
Hello World
greeting.suffix
=
!!, How are you???
let’s implement a class that maps the configuration properties into Java objects using the io.quarkus.arc.config.ConfigProperties
annotation.
Create a new class org.acme.quickstart.GreetingConfiguration.java
:
package
org
.
acme
.
quickstart
;
import
java.util.List
;
import
java.util.Optional
;
import
javax.validation.constraints.Max
;
import
javax.validation.constraints.Min
;
import
io.quarkus.arc.config.ConfigProperties
;
@ConfigProperties
(
prefix
=
"greeting"
)
public
class
GreetingConfiguration
{
public
String
message
;
public
String
suffix
=
"!"
;
}
Sets this as a configuration POJO with a common prefix
Maps the
greeting.message
propertyThe default value for
greeting.suffix
in case the property is not set
One of the important things to notice in the preceding code is that the prefix
attribute is not mandatory.
If it is not set, then the prefix to be used will be determined by the class name (removing the suffix part Configuration
).
In this case, the prefix
attribute could be auto-resolved to greeting
.
Then you can inject this configuration POJO to start consuming the configuration values.
You can modify the org.acme.quickstart.GreetingResource.java
class to inject this class:
@Inject
GreetingConfiguration
greetingConfiguration
;
@GET
@Path
(
"/configurations"
)
@Produces
(
MediaType
.
TEXT_PLAIN
)
public
String
helloConfigurations
(
)
{
return
greetingConfiguration
.
message
+
greetingConfiguration
.
suffix
;
}
And in a terminal window make a request to /hello/configurations
to see that the configuration values are populated inside Java, for instance:
curl http://localhost:8080/hello/configurations
Hello World!!, How are you???
As you can now see, you don’t need to annotate every field by using @ConfigProperty
—you just leverage the class definition to get the property name or the default value.
Discussion
Furthermore, Quarkus supports nested object configuration so that you can also map subcategories by using inner classes.
Suppose we add a new property named greeting.output.recipients
in
application.properties:
greeting.output.recipients
=
Ada,Alexandra
You could use an inner class to map it into the configuration object.
Modify the class org.acme.quickstart.GreetingConfiguration.java
. Then add a new inner class representing the subcategory output
and register it as a field:
public
OutputConfiguration
output
;
public
static
class
OutputConfiguration
{
public
List
<
String
>
recipients
;
}
Then you can access the greetingConfiguration.output.recipients
field to get the value.
You can also annotate the fields with Bean Validation annotations to validate at start-up time that all configuration values are valid.
If they are not valid, the application will fail to start and will indicate the validation errors in the log.
4.12 Validating Configuration Values
Solution
Use the Bean Validation specification to validate that a property value is valid when it is injected using the @ConfigProperty
annotation on a class.
The Bean Validation spec allows you to set constraints on objects using annotations. Quarkus integrates the Eclipse MicroProfile Configuration spec with the Bean Validation spec so you can use them together to validate that a configuration value meets certain criteria. This verification is executed at boot time, and if there is any violation, an error message is shown in the console and the boot process is aborted.
The first thing you need to do is to register the Quarkus Bean Validation dependency. You can do it manually by editing your pom.xml or by running the next Maven command from the root directory of the project:
./mvnw quarkus:add-extension -Dextensions="quarkus-hibernate-validator"
After that, you will need to create a configuration object, which you learned about in the previous recipe.
In the next example, a constraint on the greeting.repeat
configuration property is set so that repetitions outside of the range 1–3 inclusive cannot be set.
To validate integer range, the following Bean Validation annotations are used: javax.validation.constraints.Max
and javax.validation.constraints.Min
.
Open org.acme.quickstart.GreetingConfiguration.java
and add Bean Validation annotations:
@Min
(
1
)
@Max
(
3
)
public
Integer
repeat
;
Open src/main/resources/application.properties file and set the greeting.repeat
configuration property to 7:
greeting.repeat
=
7
Start the application, and you’ll see an error message notifying that a configuration value is violating one of the defined constraints:
./mvnw compile quarkus:dev
Discussion
In this example, you’ve seen a brief introduction to Bean Validation specification, as well as some annotations you can use to validate fields. However, more constraints are supported by Hibernate Validation and the Bean Validation implementation used, such as @Digits
, @Email
, @NotNull
, and @NotBlank
.
Get Quarkus Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.