计划执行与检查节点
executing-plans
按既定实施计划完成工作,保持过程检查和反馈。
maven-build-tool【效率与协作】Implements Maven build configurations including multi-module projects, dependency management with BOMs, plugin patterns, enforcer rules, and reactor builds for Java/Kotlin applications.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: maven-build-tool description: Implements Maven build configurations including multi-module projects, dependency management with BOMs, plugin patterns, enforcer rules, and reactor builds for Java/Kotlin applications. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: coding triggers: maven, pom.xml, mvn command, dependency management, how do i fix maven conflicts, how do i manage java dependencies, reactor build, BOM conflicts archetypes:
Implements Maven build configurations for Java and Kotlin projects — managing multi-module reactor builds, centralized dependency versioning with BOMs, plugin management with enforcer rules, and production-grade diagnostic workflows. When loaded, the model acts as a senior build engineer producing correct pom.xml files, resolving dependency conflicts, and diagnosing build issues using Maven's built-in diagnostics.
<dependencyManagement> and <pluginManagement> for all multi-module projectspom) to centralize third-party dependency versions${project.version} instead of hardcoded version numbers in child POMsmvn help:effective-pom and mvn dependency:tree -Dincludes=groupId:artifactId to diagnose issues<scope>test</scope> on all test-scoped dependencies; never leave runtime deps as test scope<exclusions> to resolve transitive dependency conflicts at the point of declarationUse this skill when:
effective-pom, dependency:tree, plugin:help)Avoid this skill for:
gradle-build-tool insteadProject Structure Design — Determine module boundaries based on cohesive package groups. Create a root pom.xml with <packaging>pom</packaging>, declare modules via <modules>, and set the parent groupId/artifactId/version.
Checkpoint: Every child module must specify <parent> referencing the root POM using relative path ../pom.xml. Verify no module declares its own groupId or version if they inherit from parent.
Dependency Management Setup — In the parent POM, declare all project dependencies inside <dependencyManagement>. For shared third-party libraries (SLF4J, Lombok, JUnit, Jackson), create a separate BOM module with pom packaging that centralizes versions.
Checkpoint: Run mvn dependency:tree -Dincludes=com.fasterxml.jackson.core from the root to verify all modules resolve the same Jackson version without conflict warnings.
Plugin Management Configuration — Centralize plugin versions in <pluginManagement> within the parent POM. Apply specific plugins to child modules by declaring them in each module's <build><plugins> section.
Checkpoint: Run mvn help:effective-pom -pl <module-name> and verify plugin versions match what you declared; Maven should not show warnings about unmanaged plugin versions.
Enforcer Rules Enforcement — Add maven-enforcer-plugin with at least three rules: enforceJavaVersion, enforceMavenVersion, and banDuplicatePomDependencies. Configure failure behavior to stop the build on violations.
Checkpoint: Run mvn enforcer:enforce from the root; verify it passes in a clean checkout and fails if you temporarily inject a duplicate dependency.
Build Verification — Execute mvn clean verify from the reactor root. Review output for version convergence warnings, plugin conflicts, or missing dependencies.
Checkpoint: All modules must compile without errors. Tests in each module must pass. The build exit code must be 0 (success).
Diagnostic Resolution — When builds fail, use Maven's diagnostic plugins: mvn help:effective-pom to see the resolved POM after interpolation and inheritance, mvn dependency:tree -Dverbose for full transitive resolution details, and mvn help:evaluate -Dexpression=property.name to inspect property values.
Checkpoint: Every dependency conflict must have an explicit <exclusion> in the module that introduces it, with a comment explaining why.
A parent POM defines shared configuration while child modules inherit and specialize. The reactor build processes all modules in declaration order, resolving inter-module dependencies.
<!-- Root pom.xml — Maven multi-module parent -->
<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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-platform</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>My Platform Parent</name>
<description>Parent POM for the My Platform multi-module project</description>
<modules>
<module>my-core</module>
<module>my-api</module>
<module>my-service</module>
<module>my-web</module>
</modules>
<!-- Centralized dependency versions -->
<dependencyManagement>
<dependencies>
<!-- Internal modules — no version needed in children (inherit from parent) -->
<dependency>
<groupId>com.example</groupId>
<artifactId>my-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Third-party dependencies with centralized versions -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.16</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Plugin versions centralized here -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- Properties for version management -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>21</maven.compiler.release>
</properties>
</project>
Child modules inherit everything from the parent. They only declare their own specific dependencies and plugin executions.
<!-- my-service/pom.xml — A child module -->
<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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Inherits groupId, version, and all management sections from parent -->
<parent>
<groupId>com.example</groupId>
<artifactId>my-platform</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>my-service</artifactId>
<name>My Service Module</name>
<description>Core business logic for the service layer</description>
<!-- Dependencies: version omitted — resolved from parent's dependencyManagement -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Exclude Log4j-over-SLF4j — causes classloader conflicts in Spring Boot -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.24.3</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.3.232</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Apply enforcer plugin execution to this module -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-rules</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireUpperBoundDeps/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
A dedicated BOM module allows the organization to manage third-party dependency versions in a single place. Child projects import it with <scope>import</scope> in their own dependencyManagement.
<!-- my-bom/pom.xml — Centralized third-party version management -->
<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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-platform</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>my-bom</artifactId>
<packaging>pom</packaging>
<name>My Platform BOM — Third-Party Dependency Versions</name>
<description>Import this BOM to use centralized third-party versions. Do not depend on this module as a library.</description>
<!-- This is NOT a dependencyManagement section — it becomes one when imported -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>4.8.179</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.3.1-jre</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.17.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Child projects import the BOM:
<dependencyManagement>
<dependencies>
<!-- Import the organization's BOM — scope=import makes it act as dependencyManagement -->
<dependency>
<groupId>com.example</groupId>
<artifactId>my-bom</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
The enforcer plugin prevents dangerous or inconsistent builds by enforcing policies at build time.
<!-- Enforcer configuration — goes in parent POM's pluginManagement -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-java-version</id>
<goals><goal>enforce</goal></goals>
<configuration>
<rules>
<requireJavaVersion>
<version>[21,)</version>
<message>ERROR: Java 21 or later is required. Found: ${java.version}</message>
</requireJavaVersion>
</rules>
</configuration>
</execution>
<execution>
<id>enforce-maven-version</id>
<goals><goal>enforce</goal></goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.9,)</version>
<message>ERROR: Maven 3.9+ is required for reproducible builds.</message>
</requireMavenVersion>
</rules>
</configuration>
</execution>
<execution>
<id>ban-duplicate-dependencies</id>
<goals><goal>enforce</goal></goals>
<configuration>
<rules>
<banDuplicatePomDependencyVersions/>
<requireUpperBoundDeps>
<excludes>
<!-- Exclude known conflicts that cannot be resolved without major refactoring -->
<exclude>org.slf4j:slf4j-api</exclude>
</excludes>
</requireUpperBoundDeps>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Maven uses a "nearest definition wins" strategy for dependency mediation. When two paths lead to different versions of the same artifact, the shorter path in the dependency tree wins. If both paths have equal depth, the first declaration in POM order wins. Understanding this is critical for resolving conflicts.
Dependency tree example:
my-service (our module)
├── my-api (1.0.0-SNAPSHOT) ← direct dep, path length 1
│ └── com.google.guava:guava:33.3.1-jre ← transitive dep, path length 2
├── commons-lang3:3.17.0 ← direct dep, path length 1
# If my-api also depended on guava:28.0-android (path length 2),
# Maven would choose 33.3.1-jre because both paths are equal depth (2),
# and guava from my-api is declared first in POM order.
# To override this, use an explicit dependency in my-service's pom.xml:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.3.1-jre</version> <!-- forces this version regardless of mediation -->
</dependency>
Centralizing versions in the parent POM (or BOM) prevents version drift and eliminates the need for children to specify versions.
<!-- ❌ BAD — Hardcoded versions scattered across child POMs, no dependencyManagement in parent -->
<!-- my-core/pom.xml -->
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.16</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version> <!-- Different version from what my-api uses -->
</dependency>
</dependencies>
<!-- my-api/pom.xml --><dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.2</version> <!-- Conflicts with my-core's 2.17.0 -->
</dependency>
</dependencies>
<!-- ✅ GOOD — Parent declares all versions in dependencyManagement using properties, children inherit without versions -->
<!-- parent/pom.xml -->
<dependencyManagement>
<properties>
<slf4j.version>2.0.16</slf4j.version>
<jackson.version>2.18.2</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- my-core/pom.xml — No version needed; inherited from parent -->
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
<!-- my-api/pom.xml — Same; no version, no conflict possible -->
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
Use these commands to diagnose build issues:
# View the fully resolved POM after all inheritance, profiles, and property interpolation
mvn help:effective-pom
# Show the dependency tree for a specific module (use -pl for project list)
mvn dependency:tree -pl my-service
# Show detailed transitive dependency resolution with version conflicts highlighted
mvn dependency:tree -Dincludes=groupId:artifactId -Dverbose
# Display all properties currently available in the build
mvn help:evaluate -Dexpression=settings.properties -q -DforceStdout
# List all profiles active for this build
mvn help:all-profiles
# Analyze dependency usage (which dependencies are used vs. declared but unused)
mvn dependency:analyze
# Resolve all dependencies and copy them to target/dependency/ (useful for offline builds)
mvn dependency:copy-dependencies
# Verify the project without running tests
mvn verify -DskipTests
# Run enforcer rules only (useful CI step before full build)
mvn enforcer:enforce
<dependencyManagement> — never let transitive dependencies pull in arbitrary versions${project.version} instead of hardcoded version numbers in child module POMsrequireJavaVersion, requireMavenVersion, and banDuplicatePomDependencyVersions rules<scope>test</scope> on every test dependency; verify no runtime dependencies leak into the compile classpath<exclusions> accompanied by a comment explaining the reasonmaven-compiler-plugin with explicit <release> (not <source> and <target>) for JDK 9+ projectsdependencyManagement<relativePath> from the parent declaration — Maven will search the local repository instead of your filesystem, causing stale builds<source> and <target> for Java version specification — use <release> (JDK 9+) or compile with a matching JDK versionmvn install to a local repository in CI builds — it pollutes the cache and hides inter-module version conflicts; use mvn clean verify insteadWhen implementing or reviewing a Maven build configuration, produce:
<dependencyManagement> and <pluginManagement> sections with all versions listedpom.xml with third-party version declarations<exclusion>, state which artifact excluded it, the version replaced, and the reason| Skill | Purpose |
|---|---|
gradle-build-tool | Alternative build tool using Gradle with Kotlin DSL, version catalogs, and configuration cache |
coding-testing | Unit test frameworks (JUnit 5, Mockito), integration testing patterns, and coverage configuration for Maven |
coding-security-review | Dependency vulnerability scanning with OWASP dependency-check-maven plugin |
Authoritative documentation links for Maven build tooling. The model follows markdown links at load time to resolve external references and inline content.