How does maven-resources-plugin work, and what does resource filtering do?
answer
- copies src/main/resources→target/classes
- filtering = ${...} token replace at build time
- binary files corrupt → nonFilteredFileExtensions
- Spring Boot uses @...@ delimiter
- process-resources / process-test-resources
basics
~10 smaven-resources-plugin copies files from src/main/resources into target/classes. With filtering enabled, it replaces ${...} placeholders in those files with property values during the copy.
solid answer
~40 smaven-resources-plugin runs at process-resources (goal `resources`) and process-test-resources (goal `testResources`), copying non-source files into `target/classes` / `target/test-classes` so they end up on the classpath / in the artifact. Its key feature is **filtering**: when a `<resource>` has `<filtering>true</filtering>`, the plugin substitutes `${property}` tokens with values from POM properties, `settings.xml`, system properties, or profile-activated values. A common use is injecting `${project.version}` or environment-specific config into `application.properties`. Pitfalls: filtering binary files can corrupt them (use `<nonFilteredFileExtensions>` or separate filtered/unfiltered resource roots), and Spring Boot remaps the default filter delimiter to `@...@` to avoid clashing with Spring's own `${...}` placeholders. Filtering happens at build time, not runtime.
code
xml · 14 lines<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes><exclude>**/*.p12</exclude></excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes><include>**/*.p12</include></includes>
</resource>
</resources>
</build>go deeper
Know it copies resources to target/classes so they end up in the jar.
Explain filtering and the ${...} substitution at build time.
Handle binary-file and delimiter pitfalls (Spring Boot @...@, nonFilteredFileExtensions).
Design per-environment config strategy (filtering vs externalized config) and its security implications for secrets.
## What it does **maven-resources-plugin** moves your *non-compiled* files (config, templates, static assets) from the source tree into the build output so they are packaged into the artifact and visible on the classpath. - Goal `resources` → bound to **process-resources**: `src/main/resources` → `target/classes`. - Goal `testResources` → bound to **process-test-resources**: `src/test/resources` → `target/test-classes`. - Goal `copy-resources` → manual, copies an arbitrary set somewhere (often used in custom executions). ## Filtering **Filtering** = token replacement during the copy. With `<filtering>true</filtering>`, every `${...}` token in the copied files is replaced by a property value resolved at build time. Sources of values: - POM `<properties>` and built-ins like `${project.version}`, `${project.artifactId}`. - `-D` system properties and environment via `${env.HOME}`. - External property files via `<filters><filter>...properties</filter></filters>`. - Active **profiles** (commonly used for per-environment config). ```xml <build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build> ``` With `app.version=${project.version}` in `application.properties`, the packaged file gets the real version baked in. ## Common gotchas - **Binary corruption**: filtering images/keystores/PDFs can break them because the plugin reads them as text. Solution: keep binaries in a separate non-filtered `<resource>` root, or set `<nonFilteredFileExtensions>` on the plugin. - **Delimiter clashes**: Spring also uses `${...}` at runtime. Spring Boot's parent POM therefore configures the resources plugin to use `@...@` as the filter delimiter, so `@project.version@` is filtered at build time and `${...}` is left for Spring at runtime. - **Build-time only**: filtering is not dynamic; values are frozen when you build. ## Inspecting `mvn process-resources` then look in `target/classes` to confirm substitution.
- Why does Spring Boot change the filtering delimiter to @...@?Because Spring uses ${...} for its own runtime property resolution. Using @...@ for Maven filtering lets build-time tokens (@project.version@) be replaced while leaving ${...} intact for Spring at runtime.
- What can go wrong if you filter a keystore or image?The plugin processes it as text and can corrupt binary content. Exclude binaries from filtering via a non-filtered resource root or nonFilteredFileExtensions.
saying these in an interview costs you the question
- Saying filtering happens at runtime — it is a build-time copy step.
- Filtering all resources including binaries without exclusions.
- Confusing resources:resources with the compiler — resources never compiles code.