Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a map property from environment variable with Spring

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!

like image 661
Zevesh Avatar asked Nov 06 '22 13:11

Zevesh


1 Answers

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> )

like image 106
Michael Michailidis Avatar answered Nov 12 '22 13:11

Michael Michailidis