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
@ConfigurationPropertiesto group together related properties - See how
@ConstructorBindinghelps you build immutable configuration objects - Understand how
@Validatedis 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.propertiesfile: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
CurrencyConfigTestin thecom.welltestedlearning.coffeekioskpackage 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
@ConfigurationPropertiesScanto the Application class (where@SpringBootApplicationis used). -
Add the following test class named
CurrencyConfigTestfor 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
@ConfigurationPropertiessupports the Bean Validation (JSR-303) standard, so we can make sure that the properties are valid before starting. -
Add
@Validatedto the class -
Add
@NotBlankto theuriTemplateinstance 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
@ConstructorBindingto the config class -
Change all of the private variables to be
final -
Remove the setter method
-
Create a constructor that takes the
uriTemplateas 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