The parent enables resource filtering with @...@ delimiters instead of the default ${...}. Why, and how would you inject the Maven build version into application.properties?
answer
- Maven default delimiter = ${...}
- Collides with Spring ${...}
- Parent sets resource.delimiter=@
- useDefaultDelimiters=false
- @project.version@ = build-time
basics
~10 sSpring's own config uses ${...} placeholders, which would collide with Maven's filtering. So the parent switches Maven's resource-filtering delimiter to @, letting you write @project.version@ in application.properties while Spring's ${...} stays untouched.
solid answer
~40 sResource filtering is a Maven feature where `maven-resources-plugin` substitutes build properties into resource files at copy time. By default Maven uses `${...}` as the placeholder delimiter — but Spring uses `${...}` extensively for property placeholders (`${DB_URL}`) and for `@Value("${...}")`. If Maven filtered those, it would try to resolve them at build time and blank out or mangle them. To avoid the clash, `spring-boot-starter-parent` sets the property `resource.delimiter` to `@` and configures `maven-resources-plugin` with `useDefaultDelimiters=false`, so **only** `@...@` tokens are filtered. Then in `application.properties` you write, e.g., `[email protected]@`, and Maven replaces it with the POM version at package time, while runtime `${...}` placeholders pass through untouched. Filtering is enabled for `src/main/resources` by the parent.
code
kotlin · 15 lines// src/main/resources/application.properties
// [email protected]@ // Maven fills at build time
// [email protected]@ // -> e.g. 1.4.0 after package
// spring.datasource.url=${DB_URL} // Spring resolves at runtime
// Read the build-time value at runtime:
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
@Component
class BuildInfo(
@Value("\${info.app.version}") val version: String,
) {
fun banner() = "Running version $version"
}go deeper
May not know filtering exists; enough to know Maven can substitute @project.version@.
Explains build-time vs runtime and that @ avoids the ${} clash.
Names resource.delimiter/useDefaultDelimiters and knows filtering is limited to configured resource dirs.
Weighs binary-resource pitfalls, custom resource dirs, and Maven-vs-Gradle mechanism differences and migration impact.
## What 'resource filtering' means In a Maven build, files under `src/main/resources` are **copied** into `target/classes` by the `maven-resources-plugin`. 'Filtering' means: during that copy, the plugin performs **variable substitution**, replacing placeholder tokens with values of Maven properties (POM coordinates like `project.version`, `project.artifactId`, values from `<properties>`, settings, etc.). It happens at **build time**, before the jar is assembled. ## The delimiter collision problem Maven's default filtering delimiter is **`${...}`**. But Spring Boot's runtime configuration mechanism *also* uses `${...}`: - Property placeholders: `spring.datasource.url=${DB_URL}` resolved at **runtime** by Spring's `PropertySourcesPlaceholderConfigurer`. - Annotations: `@Value("${server.port}")`. If Maven filtered `application.properties` with the default `${...}` delimiter, at **build time** it would try to resolve `${DB_URL}` as a Maven property, fail to find it, and either leave a warning or blank it — breaking runtime resolution. ## The parent's fix `spring-boot-starter-parent` reconfigures filtering so the two mechanisms don't collide: - It defines a property `resource.delimiter` with value `@`. - It configures `maven-resources-plugin` with that delimiter and `useDefaultDelimiters=false`, meaning the default `${...}` is **disabled** and only `@...@` is treated as a filter token. - It enables filtering on the standard resources directory. Result: a clean separation — **`@...@` = Maven build-time**, **`${...}` = Spring runtime**. ## Usage `application.properties`: ```properties [email protected]@ [email protected]@ app.datasource.url=${DB_URL} ``` After `mvn package`, the packaged file reads e.g. `app.build.version=1.4.0` while `${DB_URL}` is still literal, ready for Spring to resolve at startup. A common pairing is exposing the value via `@Value("${app.build.version}")` or Actuator info. ## Gotchas - This behavior is **inherited from the parent**. Drop the parent (use the BOM import) and you lose the `@` delimiter config — filtering reverts to `${...}` and you must reconfigure `maven-resources-plugin` yourself, or your `@...@` tokens won't be replaced. - Filtering only applies to directories marked as filtered. The parent handles `src/main/resources`; if you add custom resource dirs you must set `<filtering>true</filtering>` yourself. - Binary resources (images, keystores) should **not** be filtered — filtering them can corrupt bytes. Keep them in a non-filtered `<resource>` block. - The Gradle plugin uses a different mechanism (`processResources` with `expand`/`ReplaceTokens`); this `@...@` convention is Maven-specific.
- What would happen if Maven filtered application.properties with the default ${...} delimiter?It would try to resolve Spring's runtime placeholders like ${DB_URL} at build time, fail (they aren't Maven properties), and blank or mangle them, breaking runtime configuration.
- You switched to the spring-boot-dependencies BOM import and your @project.version@ token stopped resolving. Why?The @ delimiter and filtering config come from the parent's maven-resources-plugin setup. Without the parent you must set resource.delimiter/useDefaultDelimiters and enable filtering yourself.
saying these in an interview costs you the question
- Claiming Spring uses @...@ for runtime placeholders
- Thinking filtering happens at runtime
- Filtering binary resources like keystores