Maven Build System (CRITICAL)
July 23, 2025 · View on GitHub
Build Hierarchy Overview
parent/pom.xml # Global properties, plugin management
├── bom/application/pom.xml # Dependency management (versions)
└── dotCMS/pom.xml # Module dependencies (no versions)
Dependency Management Pattern (CRITICAL)
⚠️ ALL dependencies must follow this pattern:
1. Define Versions in BOM
Add new dependency versions to bom/application/pom.xml:
<properties>
<new-library.version>1.2.3</new-library.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>new-library</artifactId>
<version>${new-library.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
2. Reference Without Version in Modules
Use in dotCMS/pom.xml (NO version):
<dependency>
<groupId>com.example</groupId>
<artifactId>new-library</artifactId>
</dependency>
3. Existing Swagger/OpenAPI Dependencies
<!-- In bom/application/pom.xml -->
<swagger.version>2.2.0</swagger.version>
<!-- In dotCMS/pom.xml (versions inherited) -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
</dependency>
Plugin Management Pattern (CRITICAL)
⚠️ ALL plugins must follow this pattern:
1. Define in Parent POM
Add to parent/pom.xml in <pluginManagement>:
<pluginManagement>
<plugins>
<plugin>
<groupId>com.example</groupId>
<artifactId>example-maven-plugin</artifactId>
<version>1.0.0</version>
</plugin>
</plugins>
</pluginManagement>
2. Reference Without Version in Modules
Use in any module POM (NO version):
<plugin>
<groupId>com.example</groupId>
<artifactId>example-maven-plugin</artifactId>
</plugin>
Dependency Analysis & Troubleshooting
Essential Maven Commands for Dependency Management
# View complete dependency tree
./mvnw dependency:tree
# Show dependency tree for specific module
./mvnw dependency:tree -pl :dotcms-core
# Find duplicate dependencies (different versions)
./mvnw dependency:tree -Dverbose
# Analyze dependency conflicts
./mvnw dependency:analyze
# Show effective POM (with resolved versions)
./mvnw help:effective-pom
# Display dependency updates available
./mvnw versions:display-dependency-updates
# Check for plugin updates
./mvnw versions:display-plugin-updates
# Resolve dependency convergence issues
./mvnw dependency:analyze-report
Troubleshooting Common Issues
1. Version Conflicts
# Find conflicting versions
./mvnw dependency:tree -Dverbose | grep -A5 -B5 "omitted for conflict"
# Example output showing conflict:
# [INFO] +- com.fasterxml.jackson.core:jackson-core:jar:2.15.2:compile
# [INFO] | \- com.fasterxml.jackson.core:jackson-annotations:jar:2.15.2:compile
# [INFO] \- com.example:library:jar:1.0.0:compile
# [INFO] \- (com.fasterxml.jackson.core:jackson-core:jar:2.12.3:compile - omitted for conflict with 2.15.2)
2. Duplicate Dependencies
# Find duplicate JARs in classpath
./mvnw dependency:tree -Dverbose | grep -E "\+\-.*:.*:.*:.*:.*"
# Check for duplicate classes
./mvnw dependency:analyze-duplicate
3. Missing Dependencies
# Analyze used but undeclared dependencies
./mvnw dependency:analyze
# Example output:
# [WARNING] Used undeclared dependencies found:
# [WARNING] com.google.guava:guava:jar:31.1-jre:compile
4. Unused Dependencies
# Find declared but unused dependencies
./mvnw dependency:analyze | grep "Unused declared dependencies"
# Remove unused dependencies to reduce JAR size
./mvnw dependency:analyze -DfailOnWarning=true
Dependency Resolution Best Practices
1. Override Transitive Dependencies
When a transitive dependency needs a specific version:
<!-- In bom/application/pom.xml -->
<properties>
<jackson.version>2.17.2</jackson.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Force specific version for all Jackson modules -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
2. Exclude Problematic Transitive Dependencies
<!-- In dotCMS/pom.xml -->
<dependency>
<groupId>com.example</groupId>
<artifactId>library-with-conflicts</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
3. Verify Dependency Convergence
# Check that all dependencies converge to single versions
./mvnw enforcer:enforce -Denforcer.rules=DependencyConvergence
Integration with Build Pipeline
Pre-commit Checks
# Verify no dependency issues before commit
./mvnw dependency:analyze dependency:analyze-duplicate
CI/CD Pipeline Integration
# In build pipeline, fail on dependency issues
./mvnw dependency:analyze -DfailOnWarning=true
./mvnw enforcer:enforce -Denforcer.rules=DependencyConvergence
Common Dependency Patterns
1. Security Vulnerability Updates
# Check for known vulnerabilities
./mvnw org.owasp:dependency-check-maven:check
# Update vulnerable dependencies in BOM
# Always test thoroughly after security updates
2. Major Version Updates
# Before major version updates, analyze impact
./mvnw dependency:tree -Dincludes=com.fasterxml.jackson.core:*
./mvnw dependency:analyze-report
3. Dependency Scope Management
# Verify test dependencies don't leak to runtime
./mvnw dependency:tree -Dscope=runtime
./mvnw dependency:tree -Dscope=test
Key Rules (NEVER VIOLATE)
- NEVER add version numbers to dependencies in
dotCMS/pom.xml - NEVER add version numbers to plugins in module POMs
- ALWAYS add new dependency versions to
bom/application/pom.xml - ALWAYS add new plugin versions to
parent/pom.xml - ALWAYS define global properties in
parent/pom.xml - ALWAYS run
./mvnw dependency:analyzebefore major dependency changes - ALWAYS check dependency tree for conflicts:
./mvnw dependency:tree -Dverbose