Java Build Mastery: Maven & Gradle
The ultimate guide to Java build tools. Master dependency management, build lifecycles, plugins, multi-module projects, and advanced configurations.
Table of Contents
1. Maven vs Gradle Comparison
| Feature | Maven | Gradle |
|---|---|---|
| Configuration | XML (pom.xml) | Groovy/Kotlin DSL |
| Build Speed | Slower (no caching) | Faster (incremental builds + cache) |
| Learning Curve | Easier (convention-based) | Steeper (more flexible) |
| Customization | Plugin-based only | Full scripting capability |
| IDE Support | Excellent | Excellent |
| Android | Limited support | Official build tool |
| Daemon | No daemon | Background daemon |
| Repository | Central, JCenter | Central, JCenter, custom |
2. Maven Fundamentals
Maven uses a Project Object Model (POM) defined in pom.xml. It follows "Convention over Configuration" principle.
Standard Directory Structure
my-project/
├── pom.xml # Project configuration
├── src/
│ ├── main/
│ │ ├── java/ # Application source code
│ │ │ └── com/example/
│ │ │ └── App.java
│ │ └── resources/ # Configuration files
│ │ └── application.properties
│ └── test/
│ ├── java/ # Test source code
│ │ └── com/example/
│ │ └── AppTest.java
│ └── resources/ # Test resources
└── target/ # Build output (generated)Complete pom.xml Example
<?xml version="1.0" encoding="UTF-8"?>
<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>
<!-- Project Coordinates -->
<groupId>com.example</groupId>
<artifactId>my-application</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>My Application</name>
<description>A sample Maven project</description>
<!-- Properties (Variables) -->
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.boot.version>3.2.0</spring.boot.version>
</properties>
<!-- Dependencies -->
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<!-- Lombok for boilerplate reduction -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- Testing Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Build Configuration -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
</plugins>
</build>
</project>3. Maven Essential Commands
Create New Project
# Quick Start (Interactive)
mvn archetype:generate
# Non-Interactive with specific archetype
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=my-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=falseCreates a new Maven project from an archetype template.
Clean Project
mvn cleanRemoves the target/ directory containing all build outputs.
Compile Source Code
mvn compileCompiles source code in src/main/java to target/classes.
Run Tests
# Run all tests
mvn test
# Run specific test class
mvn test -Dtest=UserServiceTest
# Run specific test method
mvn test -Dtest=UserServiceTest#testCreateUser
# Run tests with pattern
mvn test -Dtest=*ServiceTestExecutes unit tests using the configured test framework.
Package Application
# Create JAR/WAR
mvn package
# Skip tests during packaging
mvn package -DskipTests
# Also skip test compilation
mvn package -Dmaven.test.skip=truePackages compiled code into distributable format (JAR/WAR) in target/.
Install to Local Repository
mvn installInstalls the package to ~/.m2/repository for use by other local projects.
Deploy to Remote Repository
mvn deployDeploys the package to a remote repository (requires distributionManagement config).
View Dependency Tree
# Full dependency tree
mvn dependency:tree
# With specific scope
mvn dependency:tree -Dscope=compile
# Output to file
mvn dependency:tree -DoutputFile=deps.txtDisplays the project's dependency tree showing all transitive dependencies.
Check for Dependency Updates
# Show available updates
mvn versions:display-dependency-updates
# Show plugin updates
mvn versions:display-plugin-updates
# Update dependencies to latest versions
mvn versions:use-latest-versionsChecks Maven Central for newer versions of dependencies.
Download Dependencies
# Download all dependencies
mvn dependency:resolve
# Download sources
mvn dependency:sources
# Download javadocs
mvn dependency:resolve -Dclassifier=javadocDownloads all dependencies to local repository for offline access.
Generate Project Site
mvn siteGenerates project documentation site with reports in target/site/.
4. Maven Build Lifecycle
Maven has three built-in lifecycles: default (build), clean, and site.
Default Lifecycle Phases
💡 Important: Each phase executes all previous phases. Running mvn install will execute: validate → compile → test → package → verify → install.
5. Maven Dependency Scopes
compile (default)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.1.0</version>
<!-- scope is 'compile' by default -->
</dependency>Available in all classpaths. Transitive dependencies included.
provided
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>Available at compile time but expected to be provided at runtime (e.g., by servlet container).
runtime
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
<scope>runtime</scope>
</dependency>Not needed for compilation but required at runtime (e.g., JDBC drivers).
test
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>Only available during test compilation and execution.
6. Maven Plugins
<build>
<plugins>
<!-- Compiler Plugin - Set Java Version -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<!-- Surefire Plugin - Unit Tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<!-- Failsafe Plugin - Integration Tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- JAR Plugin - Customize JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.App</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<!-- Shade Plugin - Create Fat JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Spring Boot Plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>7. Maven Profiles
Profiles allow you to customize builds for different environments (dev, test, prod).
<profiles>
<!-- Development Profile (Active by default) -->
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>development</env>
<db.url>jdbc:h2:mem:devdb</db.url>
</properties>
</profile>
<!-- Production Profile -->
<profile>
<id>prod</id>
<properties>
<env>production</env>
<db.url>jdbc:postgresql://prod-server:5432/db</db.url>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<optimize>true</optimize>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<!-- Integration Tests Profile -->
<profile>
<id>integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>Activate Profile
# Activate single profile
mvn package -Pprod
# Activate multiple profiles
mvn package -Pdev,integration
# List active profiles
mvn help:active-profilesUse profiles to customize builds for different environments.
8. Gradle Fundamentals
Gradle uses build.gradle (Groovy) or build.gradle.kts (Kotlin DSL). It offers flexibility, speed, and powerful scripting.
Standard Directory Structure
my-project/
├── build.gradle(.kts) # Build script
├── settings.gradle(.kts) # Settings (multi-project)
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew # Unix wrapper script
├── gradlew.bat # Windows wrapper script
├── src/
│ ├── main/
│ │ ├── java/
│ │ └── resources/
│ └── test/
│ ├── java/
│ └── resources/
└── build/ # Build output (generated)Groovy DSL (build.gradle)
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '1.0.0-SNAPSHOT'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
// Maven Local
mavenLocal()
// Custom repository
maven { url 'https://repo.example.com/maven2' }
}
dependencies {
// Implementation dependencies
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// Compile-only (like Maven's provided)
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
// Runtime only
runtimeOnly 'com.mysql:mysql-connector-j:8.2.0'
// Test dependencies
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}
tasks.named('test') {
useJUnitPlatform()
}
// Custom configuration
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}Kotlin DSL (build.gradle.kts)
plugins {
java
id("org.springframework.boot") version "3.2.0"
id("io.spring.dependency-management") version "1.1.4"
}
group = "com.example"
version = "1.0.0-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
compileOnly("org.projectlombok:lombok:1.18.30")
annotationProcessor("org.projectlombok:lombok:1.18.30")
runtimeOnly("com.mysql:mysql-connector-j:8.2.0")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.test {
useJUnitPlatform()
}9. Gradle Essential Commands
💡 Best Practice: Always use the Gradle Wrapper (./gradlew or gradlew.bat) instead of system-installed Gradle for consistent builds.
Initialize New Project
# Interactive initialization
gradle init
# Java application
gradle init --type java-application
# Java library
gradle init --type java-library
# With Kotlin DSL
gradle init --type java-application --dsl kotlinCreates a new Gradle project with the specified type.
Generate Gradle Wrapper
# Generate wrapper files
gradle wrapper
# With specific version
gradle wrapper --gradle-version 8.5
# Verify wrapper
./gradlew --versionCreates wrapper scripts for consistent Gradle version across machines.
Clean Build
# Clean build directory
./gradlew clean
# Clean and build
./gradlew clean build
# Force clean
./gradlew clean --no-build-cacheRemoves the build/ directory containing all build outputs.
Build Project
# Build (compile + test + jar)
./gradlew build
# Build without tests
./gradlew build -x test
# Build with stacktrace
./gradlew build --stacktrace
# Build with debug info
./gradlew build --debugCompiles, tests, and creates the project artifacts.
Run Tests
# Run all tests
./gradlew test
# Run specific test class
./gradlew test --tests "UserServiceTest"
# Run tests matching pattern
./gradlew test --tests "*ServiceTest"
# Run single test method
./gradlew test --tests "UserServiceTest.testCreate"
# Rerun tests (ignore cache)
./gradlew test --rerun-tasksExecutes tests with JUnit Platform support.
Run Spring Boot Application
# Run application
./gradlew bootRun
# With arguments
./gradlew bootRun --args='--server.port=9090'
# With JVM args
./gradlew bootRun -Dspring.profiles.active=devStarts the Spring Boot application with the embedded server.
View Dependencies
# All dependencies
./gradlew dependencies
# Specific configuration
./gradlew dependencies --configuration implementation
# Dependency insight for specific dependency
./gradlew dependencyInsight --dependency spring-coreDisplays the dependency tree for the project.
List All Tasks
# List available tasks
./gradlew tasks
# All tasks including hidden
./gradlew tasks --all
# Tasks for specific group
./gradlew tasks --group "build"Shows all available tasks with their descriptions.
Refresh Dependencies
# Force refresh dependencies
./gradlew build --refresh-dependencies
# Clear Gradle cache
rm -rf ~/.gradle/cachesForces Gradle to re-download all dependencies.
Gradle Daemon
# Check daemon status
./gradlew --status
# Stop all daemons
./gradlew --stop
# Run without daemon
./gradlew build --no-daemonManage the Gradle daemon for faster subsequent builds.
10. Gradle Tasks & Custom Tasks
// Simple task
tasks.register('hello') {
group = 'Custom'
description = 'Prints a greeting'
doLast {
println 'Hello from Gradle!'
}
}
// Task with dependencies
tasks.register('printVersion') {
dependsOn 'build'
doLast {
println "Version: ${project.version}"
}
}
// Copy task
tasks.register('copyResources', Copy) {
from 'src/main/resources'
into 'build/config'
include '**/*.properties'
}
// Delete task
tasks.register('cleanLogs', Delete) {
delete fileTree('logs') {
include '**/*.log'
}
}
// Task with inputs/outputs (incremental)
tasks.register('processData') {
inputs.file 'data/input.json'
outputs.file 'build/output.json'
doLast {
// Processing logic
}
}
// Task ordering
tasks.register('deploy') {
dependsOn 'build'
mustRunAfter 'test'
finalizedBy 'cleanup'
doLast {
println 'Deploying application...'
}
}
// Exec task - run external command
tasks.register('runScript', Exec) {
workingDir 'scripts'
commandLine 'bash', 'deploy.sh'
}
// Run with: ./gradlew helloKotlin DSL Custom Tasks
tasks.register("hello") {
group = "Custom"
description = "Prints a greeting"
doLast {
println("Hello from Gradle with Kotlin DSL!")
}
}
tasks.register<Copy>("copyResources") {
from("src/main/resources")
into("build/config")
include("**/*.properties")
}
tasks.register<Delete>("cleanLogs") {
delete(fileTree("logs").matching {
include("**/*.log")
})
}11. Gradle Dependencies
implementation
dependencies {
implementation 'org.springframework:spring-core:6.1.0'
}Compile-time and runtime dependency. NOT exposed to consumers (API doesn't leak).
api
dependencies {
api 'org.springframework:spring-core:6.1.0'
}Compile-time and runtime. EXPOSED to consumers. Use for library modules.
compileOnly
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
}Only for compilation, not included in runtime (like Maven's 'provided').
runtimeOnly
dependencies {
runtimeOnly 'com.mysql:mysql-connector-j:8.2.0'
}Only needed at runtime, not for compilation (e.g., JDBC drivers).
testImplementation
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
testImplementation 'org.mockito:mockito-core:5.8.0'
}Only for test compilation and execution.
12. Gradle Multi-Project Builds
my-project/
├── build.gradle
├── settings.gradle
├── app/
│ └── build.gradle
├── core/
│ └── build.gradle
└── web/
└── build.gradlerootProject.name = 'my-project'
include 'app'
include 'core'
include 'web'// Common configuration for all subprojects
subprojects {
apply plugin: 'java'
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}
tasks.named('test') {
useJUnitPlatform()
}
}
// Configure specific project
project(':web') {
dependencies {
implementation project(':core')
}
}plugins {
id 'application'
}
dependencies {
implementation project(':core')
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.0'
}
application {
mainClass = 'com.example.App'
}13. Troubleshooting Guide
Maven Troubleshooting
Force Update Snapshots
mvn clean install -UForces Maven to check for updated snapshots on remote repositories.
Debug Mode
mvn clean install -XEnables debug output for troubleshooting build issues.
Offline Mode
mvn clean install -oRuns Maven in offline mode using only cached dependencies.
Clear Local Repository
# Remove specific artifact
rm -rf ~/.m2/repository/com/example/my-artifact
# Clear entire cache (use with caution)
rm -rf ~/.m2/repositoryClears cached dependencies when you have corruption issues.
Analyze Dependencies
# Find unused/undeclared dependencies
mvn dependency:analyze
# Resolve conflicts
mvn dependency:tree -Dverbose -Dincludes=groupId:artifactIdHelps identify dependency issues and conflicts.
Gradle Troubleshooting
Build Scan
./gradlew build --scanGenerates a detailed build report to diagnose issues.
Stacktrace and Info
./gradlew build --stacktrace --infoShows full stacktrace and additional info for debugging.
Clean Cache
# Stop daemon first
./gradlew --stop
# Clear project build cache
rm -rf .gradle build
# Clear global cache
rm -rf ~/.gradle/cachesClears Gradle caches when experiencing strange build behaviors.
Check Build Configuration
# Show all properties
./gradlew properties
# Show specific project info
./gradlew projects
# Configuration report
./gradlew buildEnvironmentDisplays build configuration for debugging.
14. Best Practices
Maven Best Practices
- ✓Use Maven Wrapper (mvnw) for consistency
- ✓Define versions in <properties> section
- ✓Use dependencyManagement for multi-module
- ✓Keep pom.xml organized and well-commented
- ✓Use profiles for different environments
- ✓Pin plugin versions explicitly
- ✓Use BOM for dependency version management
Gradle Best Practices
- ✓Always use Gradle Wrapper (gradlew)
- ✓Prefer Kotlin DSL for type safety
- ✓Enable build cache for faster builds
- ✓Use implementation over compile (deprecated)
- ✓Configure parallel execution
- ✓Use version catalogs for dependency management
- ✓Leverage the Gradle daemon
💡 Which Tool Should You Choose?
Choose Maven When:
- • Your team is familiar with XML
- • You want convention over configuration
- • Using enterprise Java with stable setup
- • Project structure is simple and standard
Choose Gradle When:
- • Building Android applications
- • Need complex multi-module projects
- • Build performance is critical
- • Need custom build logic flexibility
Performance Optimization Tips
Maven
# Enable parallel builds
mvn -T 4 clean install
# Skip tests for faster builds
mvn package -DskipTests
# Use specific reactor options
mvn install -pl module-name -amGradle
# gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx2gWritten by Ramjee Prasad • Backend Developer
← Back to Portfolio