I'm creating a microservice with Spring Boot that uses some properties loaded both with @Value
and @ConfigurationProperties
. Those properties will have default values defined in the application.yaml
but I want to override them with environment variables. I've manage to do it with almost every basic property type but I'm unable with maps.
This is the code that retrieves the property, so the map is found in configuration.map
:
@Data
@ConfigurationProperties(prefix = "configuration")
public class MapConfig{
private Map<String, Object> map;
}
The default values I have in the application.yaml
are:
configuration:
map:
a: "A"
b: 2
c: true
This works fine and I get a map containing those key-value entries. Problem comes when I try to initialize the map with the environment variables. I've tried with multiples variants of CONFIGURATION_MAP='{aa:"aa", bb:12, cc:true}'
and every time I start the application I get the default values defined in application.yaml
but no trace of the environment map.
I also tried adding variables like CONFIGURATION_MAP_AA='HELLO'
and I was able to put new values in my map. However all I can do is adding information but the default values I wrote in the yaml are still there. In this case I'm getting:
{
"aa": "HELLO",
"a": "A",
"b": 2,
"c": true
}
This isn't the behavior I'm looking for. I want to completely override the default map instead of adding new info. It also has the problem that keys added this way are always transformed to lowercase so I can't override keys with camelCase. And values are also casted to strings even when my map is <String,Object>
.
Can anyone tell me how to properly initialize maps with environment variables or point me in the right direction? Thanks a lot!
The problem is the order in which the properties are been loaded.
Have a look at this doc that explains the loading order. I don't know if it will be
useful for your scenario but you can try creating a profile (for example application-other.yml
) and load this. It will load after the application.yml
The cast is coming from the most general type in your list. In the end all three "name
, 1
, true
" can be Strings. I can't think of a way of loading Object
but you can recast your String on what you like ( if its needed. ) Else break it into multiple maps that are type specific ( Map<String,String> , Map<String,Boolean>, Map<String,Integer>
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With