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 of the possible configuration properties are known by the developer. 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 every single property explicitly.
For this purpose, the MapFormat annotation allows you to 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
import io.micronaut.context.annotation.ConfigurationProperties;
import javax.validation.constraints.Min;
import java.util.Map;
import io.micronaut.core.convert.format.MapFormat;
@ConfigurationProperties("my.engine")
public class EngineConfig {
public int getCylinders() {
return cylinders;
}
public void setCylinders(int cylinders) {
this.cylinders = cylinders;
}
public Map<Integer, String> getSensors() {
return sensors;
}
public void setSensors(Map<Integer, String> sensors) {
this.sensors = sensors;
}
@Min(1L)
private int cylinders;
@MapFormat(transformation = MapFormat.MapTransformation.FLAT) (1)
private Map<Integer, String> sensors;
}
@MapFormat Example
import io.micronaut.context.annotation.ConfigurationProperties
import javax.validation.constraints.Min
import io.micronaut.core.convert.format.MapFormat
@ConfigurationProperties('my.engine')
class EngineConfig {
@Min(1L)
int cylinders
@MapFormat(transformation = MapFormat.MapTransformation.FLAT) (1)
Map<Integer, String> sensors
}
@MapFormat Example
import io.micronaut.context.annotation.ConfigurationProperties
import javax.validation.constraints.Min
import io.micronaut.core.convert.format.MapFormat
@ConfigurationProperties("my.engine")
class EngineConfig {
@Min(1L)
var cylinders: Int = 0
@MapFormat(transformation = MapFormat.MapTransformation.FLAT) (1)
var sensors: Map<Int, String>? = null
}
1 | Note the transformation argument to the annotation; possible values are MapTransformation.FLAT (for flat maps) and MapTransformation.NESTED (for nested maps) |
EngineImpl
@Singleton
public class EngineImpl implements Engine {
@Override
public Map getSensors() {
return config.getSensors();
}
public String start() {
return "Engine Starting V" + getConfig().getCylinders() + " [sensors=" + getSensors().size() + "]";
}
public EngineConfig getConfig() {
return config;
}
public void setConfig(EngineConfig config) {
this.config = config;
}
@Inject
private EngineConfig config;
}
EngineImpl
@Singleton
class EngineImpl implements Engine {
@Inject EngineConfig config
@Override
Map getSensors() {
config.sensors
}
String start() {
"Engine Starting V${config.cylinders} [sensors=${sensors.size()}]"
}
}
EngineImpl
@Singleton
class EngineImpl : Engine {
override val sensors: Map<*, *>?
get() = config!!.sensors
@Inject
var config: EngineConfig? = null
override fun start(): String {
return "Engine Starting V${config!!.cylinders} [sensors=${sensors!!.size}]"
}
}
Now a map of properties can be supplied to the my.engine.sensors
configuration property.
Use Map Configuration
LinkedHashMap<String, Object> map = new LinkedHashMap(2);
map.put("my.engine.cylinders", "8");
LinkedHashMap<Integer, String> map1 = new LinkedHashMap(2);
map1.put(0, "thermostat");
map1.put(1, "fuel pressure");
map.put("my.engine.sensors", map1);
ApplicationContext applicationContext = ApplicationContext.run(map, "test");
Vehicle vehicle = applicationContext.getBean(Vehicle.class);
DefaultGroovyMethods.println(this, vehicle.start());
Use Map Configuration
ApplicationContext applicationContext = ApplicationContext.run(
['my.engine.cylinders': '8', 'my.engine.sensors': [0: 'thermostat', 1: 'fuel pressure']],
"test"
)
Vehicle vehicle = applicationContext
.getBean(Vehicle)
println(vehicle.start())
Use Map Configuration
val subMap = mapOf(
0 to "thermostat",
1 to "fuel pressure"
)
val map = mapOf(
"my.engine.cylinders" to "8",
"my.engine.sensors" to subMap
)
val applicationContext = ApplicationContext.run(map, "test")
val vehicle = applicationContext.getBean(Vehicle::class.java)
DefaultGroovyMethods.println(this, vehicle.start())
The above example prints: "Engine Starting V8 [sensors=2]"