How do you enable the candidate index in a build, and what exactly does the generated META-INF/spring.components file contain?
answer
- annotationProcessor / optional Maven dep
- no @EnableIndex — file presence flips the switch
- className=stereotype1,stereotype2
- values are FQ annotation types (Component, Entity)
- COMPONENTS_RESOURCE_LOCATION = META-INF/spring.components
basics
~20 sAdd the spring-context-indexer as an annotation processor (Maven optional dependency or Gradle annotationProcessor). It runs at compile time and writes META-INF/spring.components, where each line maps a class name to the comma-separated stereotype annotations it has.
solid answer
~30 sYou enable it by adding org.springframework:spring-context-indexer to the build as an annotation processor — in Gradle via the annotationProcessor configuration, in Maven as an optional/provided dependency (it hooks into javac's annotation processing). During compilation it discovers types annotated with anything meta-annotated by @Indexed, plus well-known Jakarta/Java EE annotations, and writes META-INF/spring.components onto the classpath. The file is a plain properties file: each line is fullyQualifiedClassName=stereotype1,stereotype2. The stereotype values are the fully-qualified annotation types, e.g. org.springframework.stereotype.Component or jakarta.persistence.Entity. No @ComponentScan change or extra flag is needed — the mere presence of the file switches Spring to index mode at startup.
code
java · 15 lines// build.gradle
// dependencies {
// annotationProcessor 'org.springframework:spring-context-indexer'
// }
// Maven
// <dependency>
// <groupId>org.springframework</groupId>
// <artifactId>spring-context-indexer</artifactId>
// <optional>true</optional>
// </dependency>
// Resulting META-INF/spring.components:
// com.example.OrderService=org.springframework.stereotype.Component
// com.example.Customer=jakarta.persistence.Entitygo deeper
Know it needs the spring-context-indexer processor and produces META-INF/spring.components.
Explain the processor wiring (annotationProcessor/optional dep), the class=stereotypes line format, and that presence alone enables it.
Add which annotations are indexed (Indexed meta-annotations plus Jakarta EE ones) and how CandidateComponentsIndexLoader merges files.
Discuss build-tooling pitfalls: incremental compilation, IDEs skipping the processor, and keeping the index complete across all modules.
## Enabling it The index is produced by the `spring-context-indexer` **annotation processor** (artifact `org.springframework:spring-context-indexer`). You register it with your compiler: - **Gradle:** `annotationProcessor 'org.springframework:spring-context-indexer'` - **Maven:** add it as a dependency with `<optional>true</optional>` (or wire it via `maven-compiler-plugin`'s `annotationProcessorPaths`). It is compile-time only and must not leak to the runtime classpath as a normal dependency. There is **no** `@EnableIndex` annotation and no `@ComponentScan` attribute. Presence of `META-INF/spring.components` on the runtime classpath is what turns index mode on. ## What gets indexed The processor uses several `StereotypesProvider` strategies: - **@Indexed meta-annotations** — any type annotated with an annotation that is (transitively) meta-annotated with `@Indexed`. This covers `@Component` and all Spring stereotypes. - **Standard EE/Jakarta annotations** — e.g. `jakarta.persistence.Entity`, `jakarta.persistence.Converter`, `jakarta.annotation.ManagedBean`, `jakarta.inject.Named` (and their legacy `javax.*` equivalents). - **package-info** stereotypes. ## File format `META-INF/spring.components` is a properties-style text file. Each entry: ``` com.example.OrderService=org.springframework.stereotype.Component com.example.Customer=jakarta.persistence.Entity com.example.AuditController=org.springframework.stereotype.Component ``` The **key** is the fully-qualified class name; the **value** is a comma-separated list of the stereotype annotation types that class carries. A class can appear once with multiple stereotypes. ## Runtime loading `CandidateComponentsIndexLoader` reads every `spring.components` resource (constant `COMPONENTS_RESOURCE_LOCATION = "META-INF/spring.components"`) via the classloader, merges them, and caches a `CandidateComponentsIndex` per classloader. `CandidateComponentsIndex.getCandidateTypes(basePackage, stereotype)` answers scans. ## Gotcha Because it is generated at **compile time**, adding a new component without recompiling with the processor active means the index is stale. In practice a normal build regenerates it, but misconfigured incremental builds or IDE compilation without the processor can produce an incomplete index.
- Do you need to change @ComponentScan or add a flag to activate the index?No. There is no annotation attribute or property to turn it on. Spring auto-detects META-INF/spring.components on the classpath and switches to index mode; the only related property is spring.index.ignore to force it OFF.
- What is the value part of each spring.components line?A comma-separated list of the fully-qualified stereotype annotation types the class carries, e.g. org.springframework.stereotype.Component or jakarta.persistence.Entity — not the class's own annotations verbatim but the recognized stereotypes.
saying these in an interview costs you the question
- Saying you enable it with an @Enable... annotation or @ComponentScan attribute
- Shipping spring-context-indexer as a normal runtime dependency instead of a compile-time processor
- Thinking the file lists methods or bean names rather than class -> stereotypes
- Assuming it is generated at runtime