Spring @Value - Is there a way to assign a default empty map?

Viewed 3580

Situation

I am using @PropertySource in my class along with @Value in order to inject a value to a map from a properties file. The code for that is as follows:

@Value("#{${global.fieldsSubset}}")
private final Map<String, Set<String>> fieldsSubset = new HashMap<>();

In case the required property isn't found I'd like to initialize the map as an empty map. For that I changed the code to:

@Value("#{${global.fieldsSubset : {:}}}")
private final Map<String, Set<String>> fieldsSubset = new HashMap<>();

Problem

The default behavior works fine and the map is empty when the property isn't found, but when the property is present the default value still remains and the map is always empty.

Here is the whole class:

@Configuration
@PropertySource(value = "classpath:global.properties", ignoreResourceNotFound = true)
@RefreshScope
public class FieldsSubsetsProperties {
    @Value("#{${global.fieldsSubset:{:}}}")
    private final Map<String, Set<String>> fieldsSubset = new HashMap<>();

    public Map<String, Set<String>> getFieldsSubset() {
        return fieldsSubset;
    }

    public Set<String> getSubsetOfFieldsNames(String subsetName) {
        return fieldsSubset.getOrDefault(subsetName, 
     Collections.emptySet());
    }
}

Here is the property value:

global.fieldsSubset = {\
 'channel-basic':{'id', 'number', 'name'}, \
 'channel':{'id', 'number', 'name', 'description', 'status'}\
}
4 Answers

Try this:

@Value("#{${global.fieldsSubset:{T(java.util.Collections).emptyMap()}}}")
private final Map<String, Set<String>> fieldsSubset = new HashMap<>();

I think you have 2 errors:

  1. In the declaration of the field, the final is wrong. The field must be non-final, so that Spring can set its value after constructing the bean instance
  2. The JSON is wrong. A Set is mapped to a JSON list, so the JSON should be i.e. 'channel':['id', 'number', 'name', 'description', 'status'], meaning you should use brackets instead of braces for the values of the map

Try using the Elvis operator

@Value("#{${global.fieldsSubset} ?: { : }}")
private final Map<String, Set<String>> fieldsSubset = new HashMap<>();
Related