Java Build Tools — Maven & Gradle Guide
In this tutorial, you'll learn about Java Build Tools. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Java build tools automate compiling code, managing dependencies, running tests, and packaging — replacing manual javac commands with reproducible build scripts.
Why Build Tools Matter
Imagine compiling a project with 200 dependencies, each with its own version. Doing that by hand is impossible. Build tools resolve transitive dependencies, run tests in the right order, package JARs and WARs, and integrate with CI/CD pipelines. DodaTech's Doda Browser uses Gradle with 150+ modules, producing distinct artifacts for desktop, mobile, and server targets. Every build is reproducible, auditable, and automated. Related concepts include Java testing for build-integrated test suites and Java I/O for resource handling during builds.
Learning Path
graph LR
A[Java Basics] --> B[Maven Fundamentals]
B --> C[Build Lifecycle & Plugins]
C --> D[Dependency Management]
D --> E[Multi-Module Projects]
E --> F[Gradle & Groovy/Kotlin DSL]
F --> G[CI/CD Integration]
style B fill:#f59e0b,color:#fff,stroke-width:3px
Maven: Convention Over Configuration
Maven uses an XML file (pom.xml) and follows a strict convention: source code goes in src/main/java, tests in src/test/java, resources in src/main/resources. This convention means any developer can open any Maven project and know exactly where to find things.
Project Object Model (pom.xml)
<?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>
<groupId>com.dodatech</groupId>
<artifactId>file-scanner</artifactId>
<version>2.1.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.dodatech.scanner.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
Every POM has a groupId (your organization), artifactId (project name), and version. Dependencies declare their coordinates plus an optional scope — compile (default, available everywhere), test (only during testing), provided (supplied by the runtime environment). Maven downloads dependencies from Maven Central, the largest Java package registry.
Maven Build Lifecycle
Maven's build lifecycle has three built-in phases sequences: default (build and deploy), clean (delete build artifacts), and site (generate documentation). The default lifecycle includes:
# Validate: check project structure
mvn validate
# Compile: compile source code
mvn compile
# Test: run tests with surefire plugin
mvn test
# Package: create JAR/WAR
mvn package
# Verify: run integration tests
mvn verify
# Install: copy artifact to local repository
mvn install
# Deploy: copy artifact to remote repository
mvn deploy
Each phase executes all previous phases. mvn test also runs validate and compile automatically. This is called phase ordering — you never skip intermediary steps.
Expected output from mvn clean package:
[INFO] Scanning for projects...
[INFO] Building file-scanner 2.1.0
[INFO] --- maven-clean-plugin:3.2.0:clean (default-clean) ---
[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) ---
[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) ---
[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) ---
[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) ---
[INFO] --- maven-surefire-plugin:3.2.5:test (default-test) ---
[INFO] --- maven-jar-plugin:3.4.1:jar (default-jar) ---
[INFO] BUILD SUCCESS
Gradle: Flexibility and Performance
Gradle uses a Groovy or Kotlin DSL instead of XML. Build scripts are shorter, and Gradle's incremental build tracks which files changed since the last build — unchanged files aren't recompiled.
Gradle Build Script
plugins {
id 'java'
id 'application'
}
group = 'com.dodatech'
version = '2.1.0'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.code.gson:gson:2.11.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
}
application {
mainClass = 'com.dodatech.scanner.Main'
}
tasks.named('test') {
useJUnitPlatform()
testLogging {
events 'passed', 'failed', 'skipped'
}
}
Gradle's DSL reads like code. implementation replaces Maven's compile scope. testImplementation replaces test scope. The java plugin adds compilation, testing, and JAR tasks. Gradle doesn't require a fixed directory structure — you can configure source sets.
# Build the project
gradle build
# Run tests with detailed output
gradle test --info
# Run the application
gradle run
# Clean build artifacts
gradle clean
Expected output from gradle build:
> Task :compileJava
> Task :processResources
> Task :classes
> Task :jar
> Task :assemble
> Task :compileTestJava
> Task :processTestResources
> Task :testClasses
> Task :test
> Task :check
> Task :build
BUILD SUCCESSFUL in 3s
3 actionable tasks: 3 executed
Maven vs Gradle at a Glance
| Aspect | Maven | Gradle |
|---|---|---|
| Build file | XML (pom.xml) | Groovy/Kotlin DSL |
| Performance | Good (no cache by default) | Faster (incremental builds, build cache) |
| Learning curve | Moderate (XML is verbose but simple) | Steeper (DSL is powerful but complex) |
| Convention | Strict (opinionated directory layout) | Flexible (configurable source sets) |
| Dependency resolution | Centralized (Maven Central) | Centralized + dynamic versions |
| Multi-module | Parent POM with modules | Root project with subprojects |
| Plugin ecosystem | Mature (thousands of plugins) | Growing (Gradle Plugin Portal) |
| CI integration | Excellent (supported everywhere) | Excellent (Gradle Build Scans) |
Multi-Module Maven Project
Real projects split into modules — a shared library, a REST API, a CLI client. Maven handles this with a parent POM.
<!-- Parent pom.xml -->
<project>
<groupId>com.dodatech</groupId>
<artifactId>platform-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>shared-lib</module>
<module>rest-api</module>
<module>cli-client</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<dependencyManagement> defines versions in one place. Child modules omit the version:
<!-- cli-client/pom.xml -->
<project>
<parent>
<groupId>com.dodatech</groupId>
<artifactId>platform-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>cli-client</artifactId>
<dependencies>
<dependency>
<groupId>com.dodatech</groupId>
<artifactId>shared-lib</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<!-- version inherited from parent -->
</dependency>
</dependencies>
</project>
Expected output from mvn install in the parent directory:
[INFO] Reactor Build Order:
[INFO] platform-parent (pom) [1.0.0]
[INFO] shared-lib (jar) [1.0.0]
[INFO] rest-api (jar) [1.0.0]
[INFO] cli-client (jar) [1.0.0]
[INFO] BUILD SUCCESS
Maven builds modules in dependency order. shared-lib builds first because cli-client depends on it. This reactor build is why Maven is the standard for enterprise monorepos.
Common Errors in Build Tools
| Error | Cause | Fix |
|---|---|---|
Could not find artifact |
Dependency doesn't exist or Repository is missing | Add correct Repository (Maven Central, JitPack) and check GAV coordinates |
Failed to execute goal compile |
Java version mismatch between source and compiler | Set maven.compiler.source and maven.compiler.target correctly |
Cannot resolve symbol in IDE |
IDE uses wrong build tool or module graph | Re-import project: IntelliJ → Reimport, Eclipse → Update Project |
Duplicate classes |
Two dependencies contain the same class | Use mvn dependency:tree to find the conflict and exclude one |
Task with path 'run' not found in Gradle |
Missing application plugin |
Add id 'application' and configure mainClass |
Could not determine Java version |
JDK not set or Gradle wrapper wrong | Run java --version to check JDK, update gradle-wrapper.properties |
Build failed with an exception (Gradle daemon) |
Gradle daemon is corrupted | Kill daemon: gradle --stop, then rebuild |
Security Angle: Dependency Vulnerability Scanning
Build tools are a security vector. A compromised dependency injects malware into your application. DodaTech's CI pipeline includes:
<!-- Maven OWASP Dependency Check plugin -->
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>10.0.0</version>
<configuration>
<failBuildOnCVSS>7</failBuildOnCVSS>
<formats>
<format>HTML</format>
<format>JSON</format>
</formats>
</configuration>
</plugin>
Run it with:
mvn dependency-check:check
This plugin queries the National Vulnerability Database (NVD) and fails the build if any dependency has a known vulnerability with CVSS score above 7. DodaTech also runs gradle dependencies --scan to generate build scans that visualize the entire dependency tree, revealing hidden transitive dependencies that might carry vulnerabilities.
Practice Questions
- What is the difference between Maven's
compileandtestdependency scopes? - How does Gradle's incremental build improve performance?
- What is the purpose of
dependencyManagementin a parent POM? - Why does
mvn testalso runcompile? - How does the OWASP Dependency Check plugin improve security?
Answers:
compilescope makes dependencies available during compilation and at runtime.testscope restricts them to test compilation and execution only — they're excluded from the final JAR/WAR.- Gradle tracks inputs and outputs of each task. If a source file hasn't changed since the last build, Gradle skips its compilation. This makes subsequent builds 10-100x faster than Maven's full rebuild.
dependencyManagementcentralizes dependency versions for all child modules. Child modules declare dependencies without versions, reducing duplication and ensuring every module uses the same version.- Maven phases are ordered.
testcomes aftercompilein the default lifecycle. Runningtesttriggers all previous phases first, ensuring code is compiled before tests attempt to run. - It queries the NVD to find known CVEs in dependencies. With
failBuildOnCVSS, it breaks the build when a critical vulnerability is found, preventing vulnerable code from reaching production.
Challenge
Create a multi-module Maven project with:
- A
shared-libmodule containing aStringUtilsutility class - A
rest-apimodule that depends onshared-liband uses JAX-RS - A
cli-clientmodule that depends onshared-liband uses Picocli - A parent POM with
dependencyManagementfor JUnit 5, Gson, and JAX-RS - The OWASP Dependency Check plugin configured in the parent
Real-World Task: CI/CD Build Pipeline
Set up a GitHub Actions workflow for a multi-module Maven project that:
- Caches the Maven local Repository for faster builds
- Runs
mvn verifywith OWASP dependency check - Publishes test reports as artifacts
- Deploys the JAR to GitHub Packages on tags
DodaTech uses this exact pipeline across all its Java projects, processing over 200 builds per week with zero regressions.
Related tutorials: Java I/O — File Handling & NIO Guide, Java Testing — JUnit 5 Complete Guide
Next lesson: Java Module System (JPMS) — Complete Guide
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro