Spring Framework supports the injection of the Java Collection types List
, Set
, Map
and Properties
. You can use XML as well as annotations based configurations. We will learn Constructor, Setter, and Field injections for the collections using annotations based configurations in this article. The complete code example is available in the GitHub code repository.
I recommend understanding the basics of Dependency Injection in Spring if you are new to Spring.
Collections injection using @Autowired
All we need is annotate the Collections like List
, Set
, Map
with @Autowired
annotation. Alternatively, you can use @Inject
annotation as well. We will explored the injections through Constructor, Setters, and Field.
- Constructor Injection for Collections (List, Set, Map)
- Setter Injection for Collections (List, Set, Map)
- Field Injection of Collections using @Autowired
1. Constructor Injection for Collections (List, Set, Map)
The Java collections Constructor Injection is done using the @Autowired
annotation. Point to note is, the Spring IoC should be able to find the beans with the respective types to inject. The respective collection types are configured in CollectionsConfig.java
.
@Component public class ConstructorInjection { private List<String> names; private Set<Long> phones; private Map<Long, String> phoneNameMap; @Autowired public ConstructorInjection(List<String> names, Set<Long> phones, Map<Long, String> phoneNameMap) { this.names = names; this.phones = phones; this.phoneNameMap = phoneNameMap; } //Getter, Setter, toString() omitted for bravity }
@Configuration @ComponentScan("basic.ioc.bean.collections") public class CollectionsConfig { @Bean public List<String> namesList() { List names = new ArrayList<String>(); names.add("Salman Khan"); names.add("Hrithik Roshan"); return names; } @Bean public Set<Long> numbersBean() { Set<Long> numbers = new HashSet<>(); numbers.add(2222222222L); numbers.add(1212121212L); return numbers; } @Bean public Map<Long, String> phoneNameMapBean() { Map<Long, String> phoneNames = new HashMap<>(); phoneNames.put(888888888888L, "Ram"); phoneNames.put(777777777777L, "Bhim"); return phoneNames; } }
@Test public void testCollectionsMapping(){ ApplicationContext aContext = new AnnotationConfigApplicationContext(CollectionsConfig.class); ConstructorInjection cInjection = aContext.getBean(ConstructorInjection.class); System.out.println(cInjection); }
Output:
ConstructorInjection[names=[Salman Khan, Hrithik Roshan], phones=[1212121212, 2222222222], phoneNameMap={888888888888=Ram, 777777777777=Bhim}]
Understand the bean configurations in CollectionsConfig.java
, the method namesList()
returns List
, numbersBean()
returns Set
and the phoneNameMapBean()
returns the Map
. These are then @Autowired
in ConstructorInjection.java
.
2. Setter Injection for Collections (List, Set, Map)
All you have to do is place the @Autowired
annotations on setters and make sure the respective bean types are configured. In this case, we will use the same configurations from the previous example CollectionsConfig.java
.
@Component public class SetterInjection { private List<String> names; private Set<Long> phones; private Map<Long, String> phoneNameMap; @Autowired public void setNames(List<String> names) { this.names = names; } @Autowired public void setPhones(Set<Long> phones) { this.phones = phones; } @Autowired public void setPhoneNameMap(Map<Long, String> phoneNameMap) { this.phoneNameMap = phoneNameMap; } //toString() omitted for bravity. }
3. Field Injection for Collections using @Autowired
To make the Spring IoC do field injection, place @Autowired
annotations on the fields as shown below. And obviously, you need to configure the beans to be injected in these collections fields like CollectionsConfig.java
from the first example.
It is not recommended to use the field-based injection as it has a performance impact. Use either the constructor based injection or Setter based injection.
@Component public class FieldInjection { @Autowired //Avoid using property injection private List<String> names; @Autowired //Avoid using property injection private Set<Long> phones; @Autowired //Avoid using property injection private Map<Long, String> phoneNameMap; }
Injecting the Bean references in Collections
In the previous example, you saw List
, Set
, and Map
with wrapper classes. In the real-world, you need to inject/map collections of a user-defined bean.
The below example shows the injection of List<JbdBean>
in the BeanreferenceCollections class. It is important to learn the configurations. You can see in the output below, there are 2 JbdBean
inside the list. This is because, there are 2 Jbdbean
configured in CollectionsConfig
.
@Component public class BeanReferenceCollections { private List<JbdBean> list; @Autowired public void setList(List<JbdBean> list) { this.list = list; } @Override public String toString() { return new StringJoiner(", ", BeanReferenceCollections.class.getSimpleName() + "[", "]") .add("list=" + list) .toString(); } }
public class JbdBean { private String uuid; public void setUuid(String uuid) { this.uuid = uuid; } @Override public String toString() { return new StringJoiner(", ", JbdBean.class.getSimpleName() + "[", "]") .add("uuid='" + uuid + "'") .toString(); } }
@Configuration @ComponentScan("basic.ioc.bean.collections") public class CollectionsConfig { @Bean public JbdBean jbdBean1(){ JbdBean bean = new JbdBean(); bean.setUuid(UUID.randomUUID().toString()); return bean; } @Bean public JbdBean jbdBean2(){ JbdBean bean = new JbdBean(); bean.setUuid(UUID.randomUUID().toString()); return bean; } }
@Test public void testBeanReferenceCollections(){ ApplicationContext aContext = new AnnotationConfigApplicationContext(CollectionsConfig.class); BeanReferenceCollections beanReferCollections = aContext.getBean(BeanReferenceCollections.class); System.out.println(beanReferCollections); }
Output:
BeanReferenceCollections[list=[JbdBean[uuid='b3f5297c-112c-47de-bfd9-47ee4a23e35c'], JbdBean[uuid='85abf89c-ebc1-4ae3-8032-927636d3e6fa']]]
Inject the Sorted beans in Collections using @Order
The @Order
annotation specifies the bean orders in which they are injected, hence resulting in sorted collections.
@Configuration @ComponentScan("basic.ioc.bean.collections") public class CollectionsConfig { @Bean @Order(3) public NameBean name1(){ return new NameBean("John"); } @Bean @Order(1) public NameBean name2(){ return new NameBean("Ram"); } @Bean @Order(2) public NameBean name3(){ return new NameBean("Shyam"); } }
public class NameBean { private String name; public NameBean(String name) { this.name = name; } @Override public String toString() { return new StringJoiner(", ", NameBean.class.getSimpleName() + "[", "]") .add("name='" + name + "'") .toString(); } }
@Component public class SortedNamesCollection { private List<NameBean> names; @Autowired public void setNames(List<NameBean> names) { this.names = names; } @Override public String toString() { return new StringJoiner(", ", SortedNamesCollection.class.getSimpleName() + "[", "]") .add("names=" + names) .toString(); } }
@Test public void testSortedCollection(){ ApplicationContext aContext = new AnnotationConfigApplicationContext(CollectionsConfig.class); SortedNamesCollection collection = aContext.getBean(SortedNamesCollection.class); System.out.println(collection); }
Output:
SortedNamesCollection[names=[NameBean[name='Ram'], NameBean[name='Shyam'], NameBean[name='John']]]
Setting a default value for Collections using SpEL
SpEL stands for Spring Expression Language. It is a powerful expression language that allows programmers to query and manipulate objects at runtime. Using this we will assign default values to Collections.
Below is a simple example that shows the use of SpEL to assign an empty list value.
public class CollectionsBean { @Value("${names.list:}#{T(java.util.Collections).emptyList()}") private List<String> namesList; }
In this article, you learned how about the Mapping and Injecting Collections in Spring. Additionally, you can also use @Qualifier
annotations to select specific beans for injections. Download the code example from the GitHub code repo.
Leave A Comment