How to inject a Map using the @Value Spring Annotation?

137,085

Solution 1

I believe Spring Boot supports loading properties maps out of the box with @ConfigurationProperties annotation.

According that docs you can load properties:

my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com

into bean like this:

@ConfigurationProperties(prefix="my")
public class Config {

    private List<String> servers = new ArrayList<String>();

    public List<String> getServers() {
        return this.servers;
    }
}

I used @ConfigurationProperties feature before, but without loading into map. You need to use @EnableConfigurationProperties annotation to enable this feature.

Cool stuff about this feature is that you can validate your properties.

Solution 2

You can inject values into a Map from the properties file using the @Value annotation like this.

The property in the properties file.

propertyname={key1:'value1',key2:'value2',....}

In your code.

@Value("#{${propertyname}}")  private Map<String,String> propertyname;

Note the hashtag as part of the annotation.

Solution 3

You can inject .properties as a map in your class using @Resource annotation.

If you are working with XML based configuration, then add below bean in your spring configuration file:

 <bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
      <property name="location" value="classpath:your.properties"/>
 </bean>

For, Annotation based:

@Bean(name = "myProperties")
public static PropertiesFactoryBean mapper() {
        PropertiesFactoryBean bean = new PropertiesFactoryBean();
        bean.setLocation(new ClassPathResource(
                "your.properties"));
        return bean;
}

Then you can pick them up in your application as a Map:

@Resource(name = "myProperties")
private Map<String, String> myProperties;

Solution 4

I had a simple code for Spring Cloud Config

like this:

In application.properties

spring.data.mongodb.db1=mongodb://[email protected]

spring.data.mongodb.db2=mongodb://[email protected]

read

@Bean(name = "mongoConfig")
@ConfigurationProperties(prefix = "spring.data.mongodb")
public Map<String, Map<String, String>> mongoConfig() {
    return new HashMap();
}

use

@Autowired
@Qualifier(value = "mongoConfig")
private Map<String, String> mongoConfig;

@Bean(name = "mongoTemplates")
public HashMap<String, MongoTemplate> mongoTemplateMap() throws UnknownHostException {
    HashMap<String, MongoTemplate> mongoTemplates = new HashMap<>();
    for (Map.Entry<String, String>> entry : mongoConfig.entrySet()) {
        String k = entry.getKey();
        String v = entry.getValue();
        MongoTemplate template = new MongoTemplate(new SimpleMongoDbFactory(new MongoClientURI(v)));
        mongoTemplates.put(k, template);
    }
    return mongoTemplates;
}

Solution 5

To get this working with YAML, do this:

property-name: '{
  key1: "value1",
  key2: "value2"
}'
Share:
137,085
yathirigan
Author by

yathirigan

Solution Architect currently working with Microservices, APIs, Cloud Native Architecture for PCF PaaS

Updated on July 08, 2022

Comments

  • yathirigan
    yathirigan almost 2 years

    How can I inject values into a Map from the properties file using the @Value annotation in Spring?

    My Spring Java class is and I tried using the $, but got the following error message:

    Could not autowire field: private java.util.Map Test.standard; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'com.test.standard' in string value "${com.test.standard}"

    @ConfigurationProperty("com.hello.foo")
    public class Test {
    
       @Value("${com.test.standard}")
       private Map<String,Pattern> standard = new LinkedHashMap<String,Pattern>
    
       private String enabled;
    
    }
    

    I have the following properties in a .properties file

    com.test.standard.name1=Pattern1
    com.test.standard.name2=Pattern2
    com.test.standard.name3=Pattern3
    com.hello.foo.enabled=true
    
  • yathirigan
    yathirigan almost 9 years
    yes but, my problem is.. The Test class has its own @ConfigurationProperties prefix. So i want to use a diff prefix for this member variable alone . how can i do that ?
  • yathirigan
    yathirigan almost 9 years
    We have used Spring Cloud Config server to provide the configurations, hence class path approach might not work. And we don't use XMLs
  • luboskrnac
    luboskrnac almost 9 years
    hmm, I missed that. So I would create separate two beans with @ConfiguraitonProperties annotation and autowire them into test class.
  • dustin.schultz
    dustin.schultz about 8 years
    values must be quotes, else I get a SpelEvaluationException
  • petertc
    petertc over 7 years
    How to set default value if the property is absent to prevent exception occurred?
  • partTimeNinja
    partTimeNinja over 7 years
    If you want to use strings with whitespaces ( e.g USB Camera 0xfd120000046d0819 ) as keys, use single quotes as for values.
  • xenoterracide
    xenoterracide over 7 years
    may have worked for the OP, but question didn't specify boot, and this problem doesn't work for general Spring, without boot.
  • xenoterracide
    xenoterracide over 7 years
    what if there's a : in the key?
  • PeterK
    PeterK over 6 years
    Also seems to do type conversions e.g.: @Value("#{${double.map}}") final Map<String, Double> doubleMap
  • emanuel07
    emanuel07 almost 6 years
    How to set default value ?
  • Mukul Anand
    Mukul Anand almost 6 years
    the question is how to inject to a map using @Value annotation, but you are telling all sort of things rather than giving the answer to the question. Alternatives are okay but please stick to the answer as well
  • Mukul Anand
    Mukul Anand almost 6 years
    How to specify the same in a yml file
  • joemat
    joemat over 5 years
    @MukulAnand in yaml it looks like this propertyname : > { key1:'value', key2:'value' } Sorry, I'm not able to format the linebreaks correct
  • Mike D3ViD Tyson
    Mike D3ViD Tyson over 5 years
    "Note the hashtag as part of the annotation..."
  • David M. Karr
    David M. Karr about 5 years
    Is it actually possible to do this? I'm trying to use SPeL in code to do the same thing, but it just says "No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.lang.String>]".
  • Andrey M. Stepanov
    Andrey M. Stepanov about 5 years
    pattern "propertyname: {key1:'value1',key2:'value2',....}" does not work when injecting map from .yaml : java.lang.IllegalArgumentException: Could not resolve placeholder
  • rslj
    rslj almost 5 years
    I think your definition for the bean mongoConfig is incorrect. The method should be defined like this. public Map<String, String> mongoConfig() { return new HashMap(); }
  • Woland
    Woland over 4 years
    What if value has SpEL expression with '? :(
  • g00glen00b
    g00glen00b over 4 years
    Be aware, this isn't the same as using propertyname.key1=... and propertyname.key2=.... In stead, it uses a single property called propertyname. The equivalent in YAML is to treat it as a string as well and by wrapping it in quotes, such as: "{key1:'value1',key2:'value2',....}". For more infor, check this question.
  • Agoston Horvath
    Agoston Horvath over 4 years
    this is probably the most elegant way if you simply want to inject a map from application.yml
  • PAA
    PAA about 4 years
    @MikeD3ViDTyson - Could you please guide me here: stackoverflow.com/questions/60899860/… ?
  • PAA
    PAA about 4 years
    @Arpit - Could you please guide me here : stackoverflow.com/questions/60899860/…?
  • Brunke
    Brunke almost 4 years
    Thank you for answering the actual question that was asked!!! The chosen answer may have been what the OP wanted to know. But, this answer actually answered the question THAT WAS ASKED!! Huge help!!! Thanks!
  • Francois Marot
    Francois Marot over 3 years
    you can set the default value like this for an empty map: @Value("#{${tomcat.oleaconfig:{:}}}")
  • Artanis Zeratul
    Artanis Zeratul about 3 years
    how about Map<String, List<String>>? Is this possible?
  • Simon Logic
    Simon Logic over 2 years
    how to make proper fallback to empty map if property is not found? otherwise context won't be initialized.