Lab 14: Configuration
Continue with Profiles and ConfigurationProperties immutable classes validation
Description¶
To make it easier to organize and test configuration properties, it's useful to group them together in an immutable object that can be validation.
Goals¶
- Use
@ConfigurationProperties
to group together related properties - See how
@ConstructorBinding
helps you build immutable configuration objects - Understand how
@Validated
is used to validate properties
a. Property Object¶
We'll move the currency conversion service URI template into a single configuration object to make it easily injectable.
-
Add the following entry to the
application.properties
file:currency.uri-template=http://jitterted-currency-conversion.herokuapp.com/convert?from={from}&to={to}&amount={amount}
Relaxed Binding
Property files should use "kebab-case" for property names and these are translated into "camel case" for you. See: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-relaxed-binding
-
Create a test class named
CurrencyConfigTest
in thecom.welltestedlearning.coffeekiosk
package and insert the following code:package com.welltestedlearning.coffeekiosk; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "currency") public class CurrencyConfig { private String uriTemplate; public setUriTemplate(String uriTemplate) { this.uriTemplate = uriTemplate; } public String getUriTemplate() { return uriTemplate; } }
-
Add the annotation
@ConfigurationPropertiesScan
to the Application class (where@SpringBootApplication
is used). -
Add the following test class named
CurrencyConfigTest
for testing the configuration:package com.welltestedlearning.coffeekiosk; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest class CurrencyConfigTest { @Autowired private CurrencyConfig currencyConfig; @Test void configLoadedWithTemplate() { assertThat(currencyConfig.getUriTemplate()) .isNotBlank(); } }
-
Run the test, and it should pass if everything is configured correctly.
b. Add Validation¶
-
The use of
@ConfigurationProperties
supports the Bean Validation (JSR-303) standard, so we can make sure that the properties are valid before starting. -
Add
@Validated
to the class -
Add
@NotBlank
to theuriTemplate
instance variable -
Try adding
@Size(max=10)
and see what happens
c. Immutable Configuration¶
Since configuration is only loaded from properties during start, we can make the configuration object immutable by adding an "all argument" constructor and the annotation @ConstructorBinding
.
-
Add
@ConstructorBinding
to the config class -
Change all of the private variables to be
final
-
Remove the setter method
-
Create a constructor that takes the
uriTemplate
as a parameter -
Run the configuration test and it should still pass.
References
Spring Bean Validation: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#validation-beanvalidation
Bean Validation Standard: https://beanvalidation.org/
YAML configuration: https://docs.spring.io/spring-boot/docs/2.4.5/reference/htmlsingle/#boot-features-external-config-yaml
Spring Profiles: https://docs.spring.io/spring-boot/docs/2.4.5/reference/htmlsingle/#boot-features-profiles
Profile-specific Configuration: https://docs.spring.io/spring-boot/docs/2.4.5/reference/htmlsingle/#boot-features-external-config-files-profile-specific
DevTools Configuration: https://docs.spring.io/spring-boot/docs/2.4.5/reference/html/using-spring-boot.html#using-boot-devtools-globalsettings