Checkpoint Lab — Maven Plugins, Lifecycle Bindings, Plugin Configuration, Executions, and Plugin Management
Prove a production-style plugin policy in a small Maven reactor: centrally manage versions, activate one explicit lifecycle execution, inspect effective configuration, break its phase ordering, repair it, and inventory the active plugin trust boundary.
Learning objectives
- Build a Maven project whose reviewed plugin versions are centrally managed and whose custom execution is explicitly activated.
- Prove which plugin configuration is inherited, which plugins are active, and which execution id ran.
-
Predict and verify artifact changes caused by moving an execution
from
prepare-packagetoverify. - Inventory active/default-bound plugin identities and repository/wrapper assumptions as build trust evidence.
- Repair the broken lifecycle ordering and leave a concise verification/cleanup record for Chapter 08.
-Dmaven.repo.local=<lab>/.lab-m2/repository.
Normal user caches/settings are not deleted or rewritten.
./mvnw, grep, find, and
sha256sum. On Windows use mvnw.cmd and
PowerShell equivalents such as Select-String,
Get-ChildItem, and Get-FileHash. The POM
model, plugin execution identity, and lifecycle ordering are
platform-independent; shell syntax is not.
1. Checkpoint scenario and acceptance contract
You own a small Java service entering CI. The parent POM is the
central plugin policy. The application activates only the custom
AntRun execution plus standard build plugins. Your job is not merely
to obtain BUILD SUCCESS; it is to prove plugin
identity, model inheritance, execution timing, and artifact effect.
CHECKPOINT ACCEPTANCE
[ ] Maven Wrapper / Maven / JDK identities recorded
[ ] isolated local repository recorded
[ ] parent pluginManagement pins reviewed plugin versions
[ ] child active-plugin list is explainable
[ ] effective POM captured
[ ] goal metadata captured for the custom plugin
[ ] write-build-marker execution id observed in logs
[ ] correct build places marker inside JAR
[ ] prediction written before phase is intentionally broken
[ ] broken verify-phase build leaves marker outside already-built JAR
[ ] repair restores prepare-package and artifact contents
[ ] plugin/source/version inventory documented
[ ] cleanup touches only disposable lab state
2. Setup — use the final parent and active child models
Use the parent POM and active child POM from Lesson 2, plus the same tiny Java source/test. The parent centrally owns Resources 3.5.0, Compiler 3.15.0, Surefire 3.5.4, JAR 3.5.1, and AntRun 3.2.0. The child activates them without repeating versions.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.academy</groupId>
<artifactId>plugin-lab-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>app</module>
</modules>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.13.4</junit.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.5.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<archive>
<manifestEntries>
<Build-Policy>academy-plugin-lab</Build-Policy>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>write-build-marker</id>
<phase>prepare-package</phase>
<goals><goal>run</goal></goals>
<configuration>
<target>
<echo file="${project.build.outputDirectory}/build-marker.txt">phase=prepare-package</echo>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.academy</groupId>
<artifactId>plugin-lab-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>app</artifactId>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin><artifactId>maven-resources-plugin</artifactId></plugin>
<plugin><artifactId>maven-compiler-plugin</artifactId></plugin>
<plugin><artifactId>maven-surefire-plugin</artifactId></plugin>
<plugin><artifactId>maven-jar-plugin</artifactId></plugin>
<plugin><artifactId>maven-antrun-plugin</artifactId></plugin>
</plugins>
</build>
</project>
3. Preflight — record immutable execution assumptions
Write evidence before changing the model. CI should be able to answer which Maven/JDK/wrapper/plugin policy produced the artifact.
cd maven-plugin-lab
REPO="$PWD/.lab-m2/repository"
mkdir -p checkpoint-evidence "$REPO"
set -o pipefail
./mvnw --version | tee checkpoint-evidence/maven-version.txt
java -version 2> checkpoint-evidence/java-version.txt
cp .mvn/wrapper/maven-wrapper.properties checkpoint-evidence/wrapper.properties
sha256sum pom.xml app/pom.xml > checkpoint-evidence/pom-input-sha256.txt
printf 'maven.repo.local=%s
' "$REPO" > checkpoint-evidence/repository.txt
4. Prediction 1 — managed policy versus active execution
Before building, write two predictions:
Prediction 1A:
The effective child POM will show versions/configuration inherited from
parent pluginManagement for the plugins the child references.
Prediction 1B:
The log will contain exactly one project-defined AntRun execution id
write-build-marker at prepare-package, and the resulting JAR will contain
build-marker.txt because that file is generated before package.
Do not treat the effective POM as execution proof; it is only half of the evidence chain.
5. Capture effective plugin configuration and goal metadata
Generate a model artifact and goal descriptor before the main build.
./mvnw -Dmaven.repo.local="$REPO" org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom -pl app -Doutput=checkpoint-evidence/effective-app.xml
./mvnw -Dmaven.repo.local="$REPO" org.apache.maven.plugins:maven-antrun-plugin:3.2.0:help -Ddetail=true -Dgoal=run | tee checkpoint-evidence/antrun-run-help.txt
grep -n -A28 -B5 'write-build-marker' checkpoint-evidence/effective-app.xml
Verify that the effective execution id, phase, goal, plugin version, and output path match the prediction. If not, stop and diagnose inheritance/profile state before running the build.
6. Execute the good build and prove artifact causality
Use clean verify so prior marker files cannot produce a
false positive.
./mvnw -Dmaven.repo.local="$REPO" clean verify | tee checkpoint-evidence/good-build.log
jar tf app/target/app-1.0.0.jar | tee checkpoint-evidence/jar-entries-good.txt
unzip -p app/target/app-1.0.0.jar build-marker.txt | tee checkpoint-evidence/marker-good.txt
unzip -p app/target/app-1.0.0.jar META-INF/MANIFEST.MF | tee checkpoint-evidence/manifest-good.txt
sha256sum app/target/app-1.0.0.jar > checkpoint-evidence/jar-good.sha256
grep 'maven-antrun-plugin:3.2.0:run' checkpoint-evidence/good-build.log > checkpoint-evidence/antrun-execution-good.txt
Expected: one
write-build-marker execution is visible; marker text is
phase=prepare-package; the marker is a JAR entry; and
the manifest contains the centrally managed
Build-Policy entry.
7. Build an explicit plugin inventory
An effective POM can be large, so the handoff needs a concise reviewed inventory. Record at minimum plugin coordinate/version, activation source, execution ids, lifecycle position, and repository policy. Include Maven core default bindings as a distinct source from POM-declared plugins.
| Plugin | Chosen / observed version | Activation source | What to prove |
|---|---|---|---|
| Resources | 3.5.0 | Child reference + parent management | Resource goals/version in effective POM/log. |
| Compiler | 3.15.0 | Child reference + parent management |
release=17; compile/testCompile execution.
|
| Surefire | 3.5.4 | Child reference + parent management | Test count/report + goal version. |
| JAR | 3.5.1 | Child reference + parent management | Manifest policy + JAR goal version. |
| AntRun | 3.2.0 | Child explicit activation + managed execution | Execution id/phase/marker artifact. |
| Maven 3.9.16 built-in default map | Includes JAR 3.5.0 / Resources 3.4.0 defaults | Maven runtime packaging mapping | Document that project pins intentionally override reviewed versions where active. |
8. Prediction 2 — deliberately move the execution too late
Edit only the parent execution phase from
prepare-package to verify. Before running,
predict what changes:
Prediction 2A:
AntRun will still execute and build-marker.txt will exist in target/classes
by the end of verify.
Prediction 2B:
The already-created JAR will NOT contain build-marker.txt because package
occurs before verify.
Prediction 2C:
The JAR checksum will differ from or relate to the good build only according
to actual packaged inputs; the late marker cannot be assumed to affect it.
The key is to predict the execution graph and artifact boundary independently.
9. Run the broken build and preserve the cause
Change the phase, then run another clean verify. Do not
run package again afterward before inspecting, because
that would hide the ordering failure.
./mvnw -Dmaven.repo.local="$REPO" clean verify | tee checkpoint-evidence/broken-phase.log
test -f app/target/classes/build-marker.txt
jar tf app/target/app-1.0.0.jar | tee checkpoint-evidence/jar-entries-broken.txt
if grep -q 'build-marker.txt' checkpoint-evidence/jar-entries-broken.txt; then
echo 'Unexpected: investigate stale/custom packaging behavior'
exit 1
else
echo 'Expected: marker generated after JAR packaging'
fi
grep 'maven-antrun-plugin:3.2.0:run' checkpoint-evidence/broken-phase.log > checkpoint-evidence/antrun-execution-broken.txt
This is a controlled lifecycle-order failure, not a plugin-resolution failure. The original evidence remains visible: plugin ran, output exists, artifact lacks it.
10. Repair only the ordering control
Restore prepare-package. Do not add a second JAR
execution, manually modify the JAR, or move the marker with a
post-build script. Rebuild from clean state and prove the original
contract again.
./mvnw -Dmaven.repo.local="$REPO" clean verify | tee checkpoint-evidence/repaired.log
jar tf app/target/app-1.0.0.jar | grep 'build-marker.txt'
unzip -p app/target/app-1.0.0.jar build-marker.txt
sha256sum app/target/app-1.0.0.jar > checkpoint-evidence/jar-repaired.sha256
11. Plugin source and prefix policy check
Record that the required build uses Apache Maven plugin coordinates
under org.apache.maven.plugins and the organization's
approved mirror/repository policy. Inspect effective settings if
needed, but do not copy real server credentials into evidence. For
security-sensitive automation or diagnosis, prefer explicit plugin
coordinates/versions rather than relying on an unexplained prefix
mapping.
12. Final verification checklist
| Check | Evidence / pass condition |
|---|---|
| Wrapper/runtime | Maven 3.9.16 and JDK identity captured. |
| Project model | Effective POM contains intended managed versions/configuration. |
| Activation | Only intended child plugins are active; custom AntRun is explicitly referenced. |
| Execution |
One write-build-marker execution at
prepare-package.
|
| Tests | Surefire reports show the expected test ran and passed. |
| Artifact | JAR contains marker and expected manifest entry. |
| Phase failure |
Broken run proves verify is too late for marker
inclusion.
|
| Repository/cache |
Only isolated .lab-m2 is used for lab state.
|
| Trust inventory | Coordinates, versions, activation source, execution ids, repository policy documented. |
| Secrets | No real repository/signing/CI credentials in POM, logs, or evidence bundle. |
13. Cleanup / rollback
Restore the good parent POM before archiving evidence. Remove only
the disposable lab tree or its target/ and
.lab-m2 directories. If you are preserving checkpoint
evidence, copy it outside the disposable directory first. No remote
repository, CI system, or shared Maven cache was modified by the
mandatory path.
Knowledge check
The custom plugin is centrally managed. What single fact proves it is also active in the application module?
The child/effective build contains an active plugin reference/execution path; then the log proves the goal actually ran.
Why does moving the marker execution to
verify create a JAR-content failure even though
Maven reports the goal ran?
Lifecycle ordering: package created the JAR before
verify generated the marker.
Why inventory Maven core default bindings separately from project pins?
They are different sources of plugin version/activation state. The Maven runtime provides defaults, while the project may deliberately override them through managed/active plugin configuration.
A short prefix resolves to an unexpected plugin group. What is the safe diagnostic move?
Use the intended fully qualified coordinate/version and inspect effective settings/pluginGroups/repository policy instead of adding arbitrary repositories or bypassing verification.
What is the production value of stable execution ids?
They make inheritance/merging, logs, incident diagnosis, and policy review traceable to a named piece of build behavior.
14. What Chapter 07 adds to the production build-engineering model
- Executable-input inventory: plugins are reviewed/pinned build dependencies, not invisible Maven features.
- Activation clarity: packaging defaults, active plugin declarations, managed policy, and direct goals are distinguishable.
- Lifecycle evidence: execution ids and phases explain ordering and artifact effects.
- Inheritance governance: parent policy is verified through effective child models, not assumed.
- Supply-chain boundary: plugin source, prefix metadata, mirrors, local repository state, and CI privileges are explicit concerns.
- Failure discipline: the team repairs the narrow model cause instead of deleting caches, duplicating plugins, or changing repositories blindly.
Chapter 08 builds on this plugin model to cover Maven properties,
profiles, settings.xml, mirrors, proxies, servers, and
environment-specific build state—where activation and
machine-specific configuration become the next source of
reproducibility/security risk.
Official references and version notes
Version-sensitive statements in this lesson were checked against Apache Maven primary documentation on 2026-08-23. The required path uses Maven 3.9.16 through Maven Wrapper 3.3.4, JDK 21 to run Maven, Java 17 as the project release target, Maven Compiler Plugin 3.15.0, Surefire 3.5.4, Maven JAR Plugin 3.5.1, Maven Resources Plugin 3.5.0, Maven Help Plugin 3.5.2, and Maven AntRun Plugin 3.2.0. Maven 4 preview-only behavior is not required in this chapter.
The checkpoint intentionally contrasts Maven 3.9.16 built-in lifecycle plugin versions with centrally selected project pins. Current standalone plugin versions should always be re-checked before future upgrades.
- Maven — Introduction to Plugins
- Maven — Guide to Configuring Plugins
- Maven — POM Reference / Plugin Management
- Maven 3.9.16 — Default Lifecycle Plugin Bindings
- Maven — Plugin Prefix Resolution
- Maven — Available Plugins
- Maven Help Plugin 3.5.2
- Maven Compiler Plugin 3.15.0
- Maven JAR Plugin 3.5.1
- Maven Resources Plugin 3.5.0
- Maven AntRun Plugin 3.2.0
- Apache Maven Wrapper
- Maven 3.9.16 Release Notes
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.