61

I've defined a map in spring as such:

<util:map id="AdditionalParams" scope="prototype" map-class="java.util.HashMap" 
          key-type="java.lang.String" value-type="java.lang.String">
    
    <entry key="Start" value="12345" />
    <entry key="Finish" value="12365" />
</util:map>

And then I'm autowiring this bean to a property defined as:

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

When doing this, the an exception get's thrown saying that:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'DutyCreator': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.Map DutyCreator.additionalParams; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=AdditionalParams)}

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=AdditionalParams)}

Any ideas?

Cheers.

Community
  • 1
  • 1
Nick
  • 709
  • 1
  • 6
  • 10

3 Answers3

121

Starting with Spring 4.3, @Autowired can inject lists and maps and the given code in the question would work:

That said, as of 4.3, collection/map and array types can be matched through Spring’s @Autowired type matching algorithm as well, as long as the element type information is preserved in @Bean return type signatures or collection inheritance hierarchies.

But with a lower Spring version, you can't autowire a collection like that. However, you can do the following:

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

or even:

@Value("#{AdditionalParams}")
private Map<String, String> additionalParams;

Check the spring docs, the tips section:

beans that are themselves defined as a collection or map type cannot be injected through @Autowired, because type matching is not properly applicable to them. Use @Resource for such beans

Tunaki
  • 132,869
  • 46
  • 340
  • 423
garst
  • 6,042
  • 1
  • 29
  • 24
  • 1
    perfect. exactly what i was looking for.. Thanks. this worked for me.. @Resource(name="AdditionalParams") – Robin Bajaj Feb 28 '13 at 21:57
  • Thanks, this was very unintuitive; I now know more about `map` and `util:map` than I wanted to :-/ – Cory Kendall Jul 05 '13 at 21:22
  • 2
    Wow, I already spent hours on this problem. Why Spring just use autowire instead of Resource? This way just make Spring so annoying to use. – Evan Hu Jan 18 '15 at 16:57
  • For those to whom this still won't help, don't forget to remove @Qualifier(name="AdditionalParams") or else it won't work. – hipokito Jul 10 '16 at 17:40
  • Does anybody have a complete working example for @Autowired? Still not working for me. – Markus Barthlen Nov 15 '18 at 09:37
  • Even as of Spring 5.1, `@Autowired` for a Map keyed by String does not seem to work, only working for me using `@Resource` – Matthew Wise Sep 14 '20 at 11:03
4

Seems like your @Qualifier(value = "AdditionalParams") is not working.

Try using the map by following annotation :

@Resource
private Properties AdditionalParams;

and keeping your applicationContext.xml file intact.

Amber
  • 1,229
  • 9
  • 29
2
@Autowired ApplicationContext ctx;
private  <T> T getBean(String qualifier, Class<T> returnType){
    //use this for loop to print all bean from ctx. so you wont miss the typo.
    /*for(String s:ctx.getBeanDefinitionNames())
        log.info(s);*/
    return ctx.getBean(qualifier, returnType);
}

// inside your call

 if(providerList == null){
       providerList = ctx.getBean("providerList", Map.class);
 }

This Solution works good to me

Ramkumar Pillai
  • 154
  • 2
  • 8