Chapter 03Lesson 05~125 minutes

Checkpoint Lab — Coordinates, Dependencies, Repositories, Metadata, Transitivity, and Version Selection

Prove the complete dependency-resolution contract by capturing Maven and Gradle graphs, intentionally controlling a version conflict, isolating dependency state, and recording immutable artifact evidence.

Checkpoint LabDependency EvidenceConflict ControlIsolationVerification

Learning objectives

  • Resolve one shared dependency family through both Maven and Gradle and explain why the initial selected versions differ.
  • Capture dependency-tree/dependencyInsight evidence plus effective repository assumptions and selected artifact identity.
  • Predict and intentionally change at least two graph/model outcomes, then verify the predictions independently.
  • Repeat resolution using isolated dependency state and distinguish cache-assisted success from clean-room reproducibility.
  • Produce a concise dependency-resolution handoff record and clean up only disposable lab state.
Version baseline — verified 2026-08-23. Examples use JDK 21 as the common lab runtime, Apache Maven 3.9.16, Apache Maven Wrapper 3.3.4 where a Maven wrapper is already present, Apache Maven Dependency Plugin 3.10.0 for dependency-tree evidence, and Gradle 9.7.1 through the Gradle Wrapper. Maven 4.0.0-rc-6 is still a release candidate and is not required here. The illustrative graph uses org.apache.commons:commons-text:1.10.0, whose published POM declares org.apache.commons:commons-lang3:3.12.0, plus a deliberate direct request for commons-lang3:3.9. Re-check current versions and metadata before reusing these examples in production.

1. Checkpoint scenario and acceptance contract

You are handing a small JVM service to a CI team. They need more than a successful build: they need to know which dependency versions were requested, which versions were selected, why each resolver made that choice, which repository policy supplied the modules, whether a clean resolver can obtain them, and which exact artifact bytes were inspected.

[ ] Maven and Gradle wrapper/tool + JDK identities recorded
[ ] same illustrative direct/transitive requests declared
[ ] Maven dependency tree captured and 3.9 selection explained
[ ] Gradle dependency graph + dependencyInsight captured and 3.12.0 selection explained
[ ] repository policy/origin assumptions captured
[ ] Prediction A made before alignment edit
[ ] both tools intentionally aligned to approved lang3 version and verified
[ ] Prediction B made before isolated-state run
[ ] fresh Maven local repository resolves expected immutable modules
[ ] fresh Gradle User Home resolves expected immutable modules
[ ] selected artifact checksum(s) recorded from disposable state
[ ] no normal user cache or production repository modified

2. Setup and preflight

Use the Maven and Gradle projects from Lesson 2, or recreate them from the complete build files below. Keep them as siblings. The required path uses Maven Central only. If internet access is unavailable, use the expected tree fixtures for the reasoning steps and label network resolution NOT EXECUTED; do not invent successful download evidence.

<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>com.example.academy</groupId>
  <artifactId>dependency-lab-maven</artifactId>
  <version>1.0.0</version>
  <properties>
    <maven.compiler.release>17</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-text</artifactId>
      <version>1.10.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>3.10.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
plugins {
    java
}

group = "com.example.academy"
version = "1.0.0"

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.apache.commons:commons-text:1.10.0")
    implementation("org.apache.commons:commons-lang3:3.9")
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

tasks.withType<JavaCompile>().configureEach {
    options.release = 17
}
java -version
cd dependency-lab/maven && ./mvnw -v
cd ../gradle && ./gradlew -version
# Record exact output; then return to dependency-lab.

3. Prediction A — resolve the initial conflict before running commands

Write your prediction first:

Maven selected commons-lang3: __________________
Reason: ________________________________________

Gradle selected commons-lang3: _________________
Reason: ________________________________________

Expected reasoning: Maven selects 3.9 because the direct request is nearer; Gradle selects 3.12.0 because its default conflict resolution selects the higher requested version. Now verify.

4. Capture resolver evidence

cd dependency-lab/maven
./mvnw -Dmaven.repo.local=.checkpoint-m2   org.apache.maven.plugins:maven-dependency-plugin:3.10.0:tree   -Dincludes=org.apache.commons:commons-text,org.apache.commons:commons-lang3
./mvnw help:effective-settings -Doutput=effective-settings.xml
./mvnw help:effective-pom -Doutput=effective-pom.xml
cd dependency-lab/gradle
GRADLE_USER_HOME="$PWD/.checkpoint-gradle-home" ./gradlew   dependencies --configuration runtimeClasspath
GRADLE_USER_HOME="$PWD/.checkpoint-gradle-home" ./gradlew   dependencyInsight --dependency commons-lang3 --configuration runtimeClasspath

Do not compare output formatting character-for-character. Compare requested versions, selected version, selection reason, and graph paths.

5. Draw the requested graph and annotate each resolver’s selected node

Same requests; resolver policy determines selected node
flowchart TD
  P["Project"] --> T["commons-text 1.10.0"]
  P --> D["commons-lang3 3.9 direct"]
  T --> X["commons-lang3 3.12.0 transitive"]
  D --> M["Maven selected: 3.9"]
  X --> M
  D --> G["Gradle selected: 3.12.0"]
  X --> G

Record the selected version next to the resolver, not next to the declaration. Requested and resolved state are different facts.

6. Make the version policy intentional

The checkpoint’s approved version is 3.12.0. Change only the direct 3.9 request to 3.12.0 in both project models. Predict the result before rerunning.

Expected Maven selected version: 3.12.0
Expected Gradle selected version: 3.12.0
Expected graph difference: no cross-version conflict for commons-lang3
Unexpected result to investigate: any resolver still reports 3.9

Rerun the same tree/insight commands. This is intentionally a minimal direct alignment; later chapters teach central Maven management/BOMs and Gradle constraints/platforms for larger estates.

7. Prediction B — clean-room dependency state

Before creating fresh state, answer: should the selected versions change merely because the cache directory is empty? For fixed immutable release requests and unchanged repository policy, the expected selected graph is the same. What changes is the amount of metadata/artifact retrieval.

# Maven: separate empty local repository
cd dependency-lab/maven
./mvnw -Dmaven.repo.local=.checkpoint-m2-fresh   org.apache.maven.plugins:maven-dependency-plugin:3.10.0:tree

# Gradle: separate empty User Home
cd ../gradle
GRADLE_USER_HOME="$PWD/.checkpoint-gradle-home-fresh" ./gradlew   dependencies --configuration runtimeClasspath

If network resolution fails, mark the check failed/not executed and diagnose repository/network policy. Do not fall back to the warm cache and call that a clean-room pass.

8. Record artifact identity from disposable state

For Maven, the isolated repository layout is predictable enough for a direct checkpoint. After alignment, locate commons-lang3-3.12.0.jar under .checkpoint-m2-fresh and hash it. For Gradle, cache internals are deliberately not a stable public API; use the dependency report to prove selection and, if you manually inspect the disposable cache, treat paths as diagnostic evidence only.

cd dependency-lab/maven
find .checkpoint-m2-fresh -name 'commons-lang3-3.12.0.jar' -print
sha256sum $(find .checkpoint-m2-fresh -name 'commons-lang3-3.12.0.jar' -print | head -n 1)

# PowerShell equivalent:
# Get-FileHash (Get-ChildItem .checkpoint-m2-fresh -Recurse -Filter commons-lang3-3.12.0.jar | Select-Object -First 1).FullName -Algorithm SHA256

Checksum equality across two clean resolutions is useful byte-identity evidence for that artifact. It is not a vulnerability scan or a provenance proof.

9. Controlled failure — wrong coordinate, no trust-boundary expansion

Change commons-text to commons-texxt in one disposable project. Predict a coordinate/repository-not-found failure. Run the graph command in isolated state, capture the causal message, then restore the coordinate. The success criterion is recovery without adding repositories, disabling TLS, bypassing checksums, or deleting shared caches.

10. Build the handoff record

Chapter 03 dependency-resolution checkpoint
Date:                       2026-08-23
JDK:                        ____________________
Maven wrapper/core:         ____________________
Gradle wrapper:             ____________________
Maven dependency plugin:    3.10.0
Repository policy:          Central-only lab / ____________________

Initial requests:
  commons-text              1.10.0
  commons-lang3 direct      3.9
  commons-lang3 transitive  3.12.0 (via commons-text)

Initial Maven selected:      ____________________
Initial Maven reason:        ____________________
Initial Gradle selected:     ____________________
Initial Gradle reason:       ____________________

Approved aligned version:    3.12.0
Maven aligned graph verified: YES / NO
Gradle aligned graph verified:YES / NO
Fresh Maven repo verified:   YES / NO / NOT EXECUTED
Fresh Gradle home verified:  YES / NO / NOT EXECUTED
lang3 3.12.0 SHA-256:        ____________________
Wrong-coordinate failure captured: YES / NO
Recovery verified:           YES / NO
Shared caches deleted:       MUST BE NO

11. Final verification checklist

Invariant Independent evidence Pass condition
requested graph known build files + commons-text published metadata direct/transitive requests correctly documented
Maven selection explained dependency:tree initial 3.9 is attributable to nearest-definition mediation
Gradle selection explained dependencies + dependencyInsight initial 3.12.0 is attributable to conflict resolution
policy intentional edited declarations + rerun graphs both select approved 3.12.0
clean resolution fresh isolated states same fixed resolved versions obtainable without normal caches
artifact identity SHA-256 in disposable state checksum recorded for exact selected JAR
failure recovery wrong-coordinate record + restored graph root cause preserved; no repository/trust expansion

12. Cleanup and rollback

Restore the correct coordinate and approved aligned version first, then run one final graph verification. Delete only the named disposable state directories after confirming your working directory.

pwd
# Inspect before deletion:
find . -maxdepth 2 -type d   \( -name '.checkpoint-m2*' -o -name '.checkpoint-gradle-home*' \) -print

# Delete only inside the disposable dependency-lab after review:
# rm -rf maven/.checkpoint-m2 maven/.checkpoint-m2-fresh
# rm -rf gradle/.checkpoint-gradle-home gradle/.checkpoint-gradle-home-fresh
Never substitute: rm -rf ~/.m2/repository, rm -rf ~/.gradle, or shared CI cache deletion. Those are broader state stores and are not required by this checkpoint.

Knowledge check

The Maven tree and Gradle insight report disagree on selected lang3 version before alignment. Does that prove one tool is wrong?

After both declarations are aligned to 3.12.0, a fresh Maven repository still resolves 3.9. What should you suspect?

The warm build succeeds but fresh isolated resolution fails with 404. Can you mark reproducibility passed?

Why is dependencyInsight especially useful in Gradle?

Why is the Maven artifact checksum recorded after the graph is aligned?

What production invariant does this chapter add?

Summary and production bridge

Chapter 03 adds dependency-resolution evidence to the build-engineering operating model: exact coordinates, metadata/transitive edges, requested versus selected versions, resolver-specific conflict reasons, repository authority, isolated cache state, and artifact identity. You can now distinguish “the build file asked for it” from “the resolver actually selected these bytes.”

Chapter 04 narrows the focus to Maven itself: installation, Maven Wrapper behavior, settings.xml, the local repository, and project bootstrap. The dependency model learned here will make Maven’s environment-specific configuration much easier to reason about.

Official references and version notes

These lessons were finalized against current primary documentation on 2026-08-23. Dependency metadata, plugin versions, repository policies, Gradle resolution behavior, and Maven/Gradle releases are version-sensitive. Verify the exact tool versions and repository policy used by your project and CI before applying production controls.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.