There are two ways to define immutable configuration. The preferred way is to define an interface that is annotated with . For example:

    @ConfigurationProperties Example

    @ConfigurationProperties Example

    1. import io.micronaut.core.bind.annotation.Bindable
    2. import javax.validation.constraints.*
    3. @ConfigurationProperties("my.engine") (1)
    4. interface EngineConfig {
    5. @Bindable(defaultValue = "Ford") (2)
    6. @NotBlank (3)
    7. String getManufacturer()
    8. @Min(1L)
    9. int getCylinders()
    10. @NotNull
    11. CrankShaft getCrankShaft() (4)
    12. @ConfigurationProperties("crank-shaft")
    13. static interface CrankShaft { (5)
    14. Optional<Double> getRodLength() (6)
    15. }
    16. }

    @ConfigurationProperties Example

    1. import io.micronaut.context.annotation.ConfigurationProperties
    2. import io.micronaut.core.bind.annotation.Bindable
    3. import javax.validation.constraints.*
    4. import java.util.Optional
    5. @ConfigurationProperties("my.engine") (1)
    6. interface EngineConfig {
    7. @get:Bindable(defaultValue = "Ford") (2)
    8. @get:NotBlank (3)
    9. val manufacturer: String
    10. @get:Min(1L)
    11. val cylinders: Int
    12. @get:NotNull
    13. val crankShaft: CrankShaft (4)
    14. @ConfigurationProperties("crank-shaft")
    15. interface CrankShaft { (5)
    16. val rodLength: Double? (6)
    17. }

    In this case what Micronaut does is provide a compilation time implementation that delegates all getters to call the method of the Environment interface.

    This has the advantage that if the application’s configuration is (for example by invoking the /refresh endpoint) then the injected interface will automatically see the new values.

    An alternative way to implement immutable configuration is to define a class and use the @ConfigurationInject annotation on a constructor of a or @EachProperty bean.

    @ConfigurationProperties Example

    @ConfigurationProperties Example

    1. import io.micronaut.context.annotation.*
    2. import io.micronaut.core.bind.annotation.Bindable
    3. import javax.annotation.Nullable
    4. import javax.validation.constraints.Min
    5. import javax.validation.constraints.NotBlank
    6. import javax.validation.constraints.NotNull
    7. @ConfigurationProperties("my.engine") (1)
    8. class EngineConfig {
    9. private final String manufacturer
    10. private final int cylinders
    11. private final CrankShaft crankShaft
    12. @ConfigurationInject (2)
    13. EngineConfig(
    14. @Bindable(defaultValue = "Ford") @NotBlank String manufacturer, (3)
    15. @Min(1L) int cylinders, (4)
    16. @NotNull CrankShaft crankShaft) {
    17. this.manufacturer = manufacturer
    18. this.cylinders = cylinders
    19. this.crankShaft = crankShaft
    20. }
    21. String getManufacturer() {
    22. return manufacturer
    23. }
    24. int getCylinders() {
    25. return cylinders
    26. }
    27. CrankShaft getCrankShaft() {
    28. return crankShaft
    29. }
    30. @ConfigurationProperties("crank-shaft")
    31. static class CrankShaft { (5)
    32. private final Double rodLength (6)
    33. @ConfigurationInject
    34. CrankShaft(@Nullable Double rodLength) {
    35. this.rodLength = rodLength
    36. }
    37. }
    38. }
    39. }

    @ConfigurationProperties Example

    1. import io.micronaut.context.annotation.*
    2. import io.micronaut.core.bind.annotation.Bindable
    3. import javax.validation.constraints.*
    4. import java.util.Optional
    5. @ConfigurationProperties("my.engine") (1)
    6. data class EngineConfig @ConfigurationInject (2)
    7. constructor(
    8. @Bindable(defaultValue = "Ford") @NotBlank (3)
    9. val manufacturer: String,
    10. @Min(1L) (4)
    11. val cylinders: Int,
    12. @NotNull val crankShaft: CrankShaft) {
    13. @ConfigurationProperties("crank-shaft")
    14. data class CrankShaft @ConfigurationInject
    15. constructor((5)
    16. private val rodLength: Double? (6)
    17. ) {
    18. fun getRodLength(): Optional<Double> {
    19. return Optional.ofNullable(rodLength)
    20. }
    21. }
    22. }

    The annotation provides a hint to Micronaut to prioritize binding values from configuration instead of injecting beans.

    There are a few exceptions to this rule. Micronaut will not perform configuration binding for a parameter if one of these conditions is met:

    • The parameter is annotated with @Value (explicit binding)

    • The parameter is annotated with @Property (explicit binding)

    • The type of the parameter is annotated with a bean scope (such as @Singleton)

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

    Configuration values can then be supplied when running the application. For example:

    Supply Configuration

    Supply Configuration

    1. ApplicationContext applicationContext = ApplicationContext.run(
    2. "my.engine.cylinders": "8",
    3. "my.engine.crank-shaft.rod-length": "7.0"
    4. )
    5. Vehicle vehicle = applicationContext.getBean(Vehicle.class)
    6. System.out.println(vehicle.start())

    Supply Configuration

    1. val map = mapOf(
    2. "my.engine.cylinders" to "8",
    3. "my.engine.crank-shaft.rod-length" to "7.0"
    4. )
    5. val applicationContext = ApplicationContext.run(map)

    The above example prints: "Ford Engine Starting V8 [rodLength=7B.0]"