How do you inject all beans of a given type at once, and what do you get when you use List, Set, or Map<String,T>?
answer
- List/Set/Array<T> = all beans of T
- Map<String,T> → key = bean name
- Map key MUST be String
- Empty candidates → throws (required), not empty list
- @Order sorts List/Set/array; Map is keyed
basics
~20 sAutowire a List<T>, Set<T>, or Map<String,T>. Spring injects every bean of type T. For the Map the keys are the bean names and the values are the beans. This is the standard way to implement plugin/strategy registries.
solid answer
~40 sDeclare the injection point as a collection of the interface type. `List<T>` or `Set<T>` receives all beans assignable to T (ordered by @Order/Ordered for List and array, arbitrary for Set unless ordered). `Map<String, T>` receives a map whose keys are the bean names and values the beans — the key type must be String because it maps to bean ids. An array `T[]` also works. This is the idiomatic pattern for a strategy/plugin registry: define an interface, register several @Component implementations, and inject `List<Strategy>`. Gotcha: if no beans of type T exist, the collection injection is still treated as required by default and throws NoSuchBeanDefinitionException — use @Autowired(required=false) or ObjectProvider.stream() to tolerate an empty set. Only beans in the current container (and parent) are collected.
code
java · 21 linespublic interface Validator { void validate(Order o); }
@Component class NotNullValidator implements Validator { public void validate(Order o){} }
@Component class AmountValidator implements Validator { public void validate(Order o){} }
@Service
public class OrderValidation {
private final List<Validator> validators; // every Validator bean
private final Map<String, Validator> byName; // {beanName -> bean}
public OrderValidation(List<Validator> validators,
Map<String, Validator> byName) {
this.validators = validators;
this.byName = byName;
}
public void run(Order o) {
validators.forEach(v -> v.validate(o));
byName.get("amountValidator").validate(o); // dispatch by bean name
}
}go deeper
Know List<T>/Map<String,T> collect all beans and that Map keys are bean names.
Explain the required-by-default empty-collection gotcha and the String-key constraint.
Add ordering semantics, self-reference exclusion, and choosing ObjectProvider.stream for laziness.
Discuss registry design, context-hierarchy visibility, and avoiding eager materialization of large candidate sets.
## Collecting every bean of a type Spring can autowire a **container-typed** injection point and fill it with *all* matching beans, which is the canonical way to build strategy/plugin registries without manually listing implementations. ### Supported target types - `T[]` — array of all beans of type T. - `List<T>` — list of all beans of type T (ordered, see below). - `Set<T>` — set of all beans of type T (a `LinkedHashSet`). - `Collection<T>` — same as List semantics. - `Map<String, T>` — keys are **bean names**, values are the beans. ```java @Component class PdfExporter implements Exporter {} @Component class CsvExporter implements Exporter {} @Service class ExportService { private final List<Exporter> exporters; // [pdfExporter, csvExporter] private final Map<String, Exporter> byName; // {"pdfExporter":..., "csvExporter":...} ExportService(List<Exporter> exporters, Map<String, Exporter> byName) { this.exporters = exporters; this.byName = byName; } } ``` ### The Map key must be String For `Map<K, T>` injection Spring only supports `K = String`; the key is always the **bean name/id**. Any other key type is not resolved as an all-beans map. This lets you look a strategy up by its registered name. ### Ordering For arrays, `List`, and `Set`, Spring **sorts** the elements by `@Order`, the `Ordered` interface, and `@Priority` (lower value = earlier). Without ordering annotations the order is essentially bean-definition/registration order and should not be relied upon. `Map` entries are keyed, not positionally sorted (a `LinkedHashMap` reflecting the same resolution order). ### The empty-collection gotcha A very common surprise: injecting `List<Foo>` when **no** `Foo` beans exist does **not** give you an empty list by default. Collection injection points are still `required`, so the container throws `NoSuchBeanDefinitionException`. To tolerate zero candidates: - `@Autowired(required = false) List<Foo> foos;` → empty list, or - inject `ObjectProvider<Foo>` and call `.stream().toList()` → empty stream when none, or - in Kotlin, a nullable/defaulted parameter. ### Self-reference exclusion When a bean of type T itself injects `List<T>`, Spring excludes the self-reference (a bean isn't added to its own collection) unless it's the only candidate — avoids trivial self-inclusion loops. ### Scope of collection Only beans registered in the current `ApplicationContext` (and its parent hierarchy) are collected. Beans in a sibling or child context are not visible. ### When to use - Strategy pattern / handler chains (validators, exporters, event handlers). - Plugin discovery where implementations are added by simply defining new @Components. - `Map<String,T>` when you need to dispatch by a name/key from configuration or a request. Use `ObjectProvider<T>.orderedStream()` instead when you want lazy, ordered iteration without materializing the whole collection eagerly.
- Why must the Map key type be String?Because the key represents the bean's name/id in the container, which is always a String. Spring's all-beans Map injection only resolves Map<String,T>; other key types aren't supported for this mechanism.
- You inject List<Handler> but no Handler beans are defined. What happens and how do you make it tolerate zero?It throws NoSuchBeanDefinitionException because collection injection is required by default. Make it tolerant with @Autowired(required=false), or inject ObjectProvider<Handler> and use stream()/orderedStream().
saying these in an interview costs you the question
- Assuming List<T> with no candidates yields an empty list by default
- Thinking Map<Long,T> or Map<SomeEnum,T> is a supported all-beans map
- Believing collection order is guaranteed without @Order/Ordered
- Claiming a bean is included in its own injected List<T> of the same type