4.4 Configuration Properties

You can create type safe configuration by creating classes that are annotated with @ConfigurationProperties.

Micronaut will produce a reflection-free @ConfigurationProperties bean and will also at compile time calculate the property paths to evaluate, greatly improving the speed and efficiency of loading @ConfigurationProperties.

An example of a configuration class can be seen below:

@ConfigurationProperties Example

  1. import io.micronaut.context.annotation.ConfigurationProperties;
  2. import javax.validation.constraints.Min;
  3. import javax.validation.constraints.NotBlank;
  4. @ConfigurationProperties("my.engine") (1)
  5. public class EngineConfig {
  6. public String getManufacturer() {
  7. return manufacturer;
  8. }
  9. public void setManufacturer(String manufacturer) {
  10. this.manufacturer = manufacturer;
  11. }
  12. public int getCylinders() {
  13. return cylinders;
  14. }
  15. public void setCylinders(int cylinders) {
  16. this.cylinders = cylinders;
  17. }
  18. public CrankShaft getCrankShaft() {
  19. return crankShaft;
  20. }
  21. public void setCrankShaft(CrankShaft crankShaft) {
  22. this.crankShaft = crankShaft;
  23. }
  24. @NotBlank (2)
  25. private String manufacturer = "Ford"; (3)
  26. @Min(1L)
  27. private int cylinders;
  28. private CrankShaft crankShaft = new CrankShaft();
  29. @ConfigurationProperties("crank-shaft")
  30. public static class CrankShaft { (4)
  31. public Optional<Double> getRodLength() {
  32. return rodLength;
  33. }
  34. public void setRodLength(Optional<Double> rodLength) {
  35. this.rodLength = rodLength;
  36. }
  37. private Optional<Double> rodLength = Optional.empty(); (5)
  38. }
  39. }

@ConfigurationProperties Example

  1. import io.micronaut.context.annotation.ConfigurationProperties
  2. import javax.validation.constraints.Min
  3. import javax.validation.constraints.NotBlank
  4. @ConfigurationProperties('my.engine') (1)
  5. class EngineConfig {
  6. @NotBlank (2)
  7. String manufacturer = "Ford" (3)
  8. @Min(1L)
  9. int cylinders
  10. CrankShaft crankShaft = new CrankShaft()
  11. @ConfigurationProperties('crank-shaft')
  12. static class CrankShaft { (4)
  13. Optional<Double> rodLength = Optional.empty() (5)
  14. }
  15. }

@ConfigurationProperties Example

  1. import io.micronaut.context.annotation.ConfigurationProperties
  2. import java.util.*
  3. import javax.validation.constraints.Min
  4. import javax.validation.constraints.NotBlank
  5. @ConfigurationProperties("my.engine") (1)
  6. class EngineConfig {
  7. @NotBlank (2)
  8. var manufacturer = "Ford" (3)
  9. @Min(1L)
  10. var cylinders: Int = 0
  11. var crankShaft = CrankShaft()
  12. @ConfigurationProperties("crank-shaft")
  13. class CrankShaft { (4)
  14. var rodLength: Optional<Double> = Optional.empty() (5)
  15. }
  16. }
1The @ConfigurationProperties annotation takes the configuration prefix
2You can use javax.validation to validate the configuration
3Default values can be assigned to the property
4Static inner classes can provided nested configuration
5Optional configuration values can be wrapped in a java.util.Optional

Once you have prepared a type safe configuration it can simply be injected into your objects like any other bean:

@ConfigurationProperties Dependency Injection

  1. @Singleton
  2. public class EngineImpl implements Engine {
  3. private final EngineConfig config;
  4. public EngineImpl(EngineConfig config) {(1)
  5. this.config = config;
  6. }
  7. @Override
  8. public int getCylinders() {
  9. return config.getCylinders();
  10. }
  11. @Override
  12. public String start() {(2)
  13. return getConfig().getManufacturer() + " Engine Starting V" + getConfig().getCylinders() +
  14. " [rodLength=" + getConfig().getCrankShaft().getRodLength().orElse(6.0d) + "]";
  15. }
  16. public final EngineConfig getConfig() {
  17. return config;
  18. }
  19. }

@ConfigurationProperties Dependency Injection

  1. @Singleton
  2. class EngineImpl implements Engine {
  3. final EngineConfig config
  4. EngineImpl(EngineConfig config) { (1)
  5. this.config = config
  6. }
  7. @Override
  8. int getCylinders() {
  9. config.cylinders
  10. }
  11. @Override
  12. String start() { (2)
  13. "${config.manufacturer} Engine Starting V${config.cylinders} [rodLength=${config.crankShaft.rodLength.orElse(6.0d)}]"
  14. }
  15. }

@ConfigurationProperties Dependency Injection

  1. @Singleton
  2. class EngineImpl(val config: EngineConfig) : Engine {(1)
  3. override val cylinders: Int
  4. get() = config.cylinders
  5. override fun start(): String {(2)
  6. return "${config.manufacturer} Engine Starting V${config.cylinders} [rodLength=${config.crankShaft.rodLength.orElse(6.0)}]"
  7. }
  8. }
1Inject the EngineConfig bean
2Use the configuration properties

Configuration values can then be supplied from one of the PropertySource instances. For example:

Supply Configuration

  1. LinkedHashMap<String, Object> map = new LinkedHashMap(1);
  2. map.put("my.engine.cylinders", "8");
  3. ApplicationContext applicationContext = ApplicationContext.run(map, "test");
  4. Vehicle vehicle = applicationContext.getBean(Vehicle.class);
  5. System.out.println(vehicle.start());

Supply Configuration

  1. ApplicationContext applicationContext = ApplicationContext.run(
  2. ['my.engine.cylinders': '8'],
  3. "test"
  4. )
  5. Vehicle vehicle = applicationContext
  6. .getBean(Vehicle)
  7. println(vehicle.start())

Supply Configuration

  1. val map = mapOf( "my.engine.cylinders" to "8")
  2. val applicationContext = ApplicationContext.run(map, "test")
  3. val vehicle = applicationContext.getBean(Vehicle::class.java)
  4. println(vehicle.start())

The above example prints: "Ford Engine Starting V8 [rodLength=6.0]"

Note for more complex configurations you can structure @ConfigurationProperties beans through inheritance.

For example creating a subclass of EngineConfig with @ConfigurationProperties('bar') will resolve all properties under the path my.engine.bar.