MapFormat

For some use cases it may be desirable to accept a map of arbitrary configuration properties that can be supplied to a bean, especially if the bean represents a third-party API where not all the possible configuration properties are known. For example, a datasource may accept a map of configuration properties specific to a particular database driver, allowing the user to specify any desired options in the map without coding each property explicitly.

For this purpose, the MapFormat annotation lets you bind a map to a single configuration property, and specify whether to accept a flat map of keys to values, or a nested map (where the values may be additional maps).

@MapFormat Example

  1. import io.micronaut.context.annotation.ConfigurationProperties;
  2. import io.micronaut.core.convert.format.MapFormat;
  3. import javax.validation.constraints.Min;
  4. import java.util.Map;
  5. @ConfigurationProperties("my.engine")
  6. public class EngineConfig {
  7. @Min(1L)
  8. private int cylinders;
  9. @MapFormat(transformation = MapFormat.MapTransformation.FLAT) (1)
  10. private Map<Integer, String> sensors;
  11. public int getCylinders() {
  12. return cylinders;
  13. }
  14. public void setCylinders(int cylinders) {
  15. this.cylinders = cylinders;
  16. }
  17. public Map<Integer, String> getSensors() {
  18. return sensors;
  19. }
  20. public void setSensors(Map<Integer, String> sensors) {
  21. this.sensors = sensors;
  22. }
  23. }

@MapFormat Example

  1. import io.micronaut.context.annotation.ConfigurationProperties
  2. import io.micronaut.core.convert.format.MapFormat
  3. import javax.validation.constraints.Min
  4. @ConfigurationProperties('my.engine')
  5. class EngineConfig {
  6. @Min(1L)
  7. int cylinders
  8. @MapFormat(transformation = MapFormat.MapTransformation.FLAT) (1)
  9. Map<Integer, String> sensors
  10. }

@MapFormat Example

  1. import io.micronaut.context.annotation.ConfigurationProperties
  2. import io.micronaut.core.convert.format.MapFormat
  3. import javax.validation.constraints.Min
  4. @ConfigurationProperties("my.engine")
  5. class EngineConfig {
  6. @Min(1L)
  7. var cylinders: Int = 0
  8. @MapFormat(transformation = MapFormat.MapTransformation.FLAT) (1)
  9. var sensors: Map<Int, String>? = null
  10. }
1Note the transformation argument to the annotation; possible values are MapTransformation.FLAT (for flat maps) and MapTransformation.NESTED (for nested maps)

EngineImpl

  1. @Singleton
  2. public class EngineImpl implements Engine {
  3. @Inject
  4. EngineConfig config;
  5. @Override
  6. public Map getSensors() {
  7. return config.getSensors();
  8. }
  9. @Override
  10. public String start() {
  11. return "Engine Starting V" + getConfig().getCylinders() +
  12. " [sensors=" + getSensors().size() + "]";
  13. }
  14. public EngineConfig getConfig() {
  15. return config;
  16. }
  17. public void setConfig(EngineConfig config) {
  18. this.config = config;
  19. }
  20. }

EngineImpl

  1. @Singleton
  2. class EngineImpl implements Engine {
  3. @Inject EngineConfig config
  4. @Override
  5. Map getSensors() {
  6. config.sensors
  7. }
  8. @Override
  9. String start() {
  10. "Engine Starting V$config.cylinders [sensors=${sensors.size()}]"
  11. }
  12. }

EngineImpl

  1. @Singleton
  2. class EngineImpl : Engine {
  3. override val sensors: Map<*, *>?
  4. get() = config!!.sensors
  5. @Inject
  6. var config: EngineConfig? = null
  7. override fun start(): String {
  8. return "Engine Starting V${config!!.cylinders} [sensors=${sensors!!.size}]"
  9. }
  10. }

Now a map of properties can be supplied to the my.engine.sensors configuration property.

Use Map Configuration

  1. Map<String, Object> map = new LinkedHashMap<>(2);
  2. map.put("my.engine.cylinders", "8");
  3. Map<Integer, String> map1 = new LinkedHashMap<>(2);
  4. map1.put(0, "thermostat");
  5. map1.put(1, "fuel pressure");
  6. map.put("my.engine.sensors", map1);
  7. ApplicationContext applicationContext = ApplicationContext.run(map, "test");
  8. Vehicle vehicle = applicationContext.getBean(Vehicle.class);
  9. System.out.println(vehicle.start());

Use Map Configuration

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

Use Map Configuration

  1. val subMap = mapOf(
  2. 0 to "thermostat",
  3. 1 to "fuel pressure"
  4. )
  5. val map = mapOf(
  6. "my.engine.cylinders" to "8",
  7. "my.engine.sensors" to subMap
  8. )
  9. val applicationContext = ApplicationContext.run(map, "test")
  10. val vehicle = applicationContext.getBean(Vehicle::class.java)
  11. println(vehicle.start())

The above example prints: "Engine Starting V8 [sensors=2]"