Java 26-Day Course - Day 22: Build Tools - Maven/Gradle

Day 22: Build Tools - Maven/Gradle

Build tools automate dependency management, compilation, testing, and packaging of projects. Think of LEGO blocks — a build tool is like a robot that automatically fetches required parts (libraries) and assembles (builds) them. Maven and Gradle are the two major players in the Java ecosystem.

Maven Project Structure and pom.xml

Maven is an XML-based build tool that follows the Convention over Configuration philosophy.

// Maven standard directory structure:
// my-project/
// ├── pom.xml                      <- Project config (core)
// ├── src/
// │   ├── main/
// │   │   ├── java/                <- Source code
// │   │   │   └── com/example/
// │   │   │       └── App.java
// │   │   └── resources/           <- Config files, static resources
// │   │       └── application.properties
// │   └── test/
// │       ├── java/                <- Test code
// │       │   └── com/example/
// │       │       └── AppTest.java
// │       └── resources/           <- Test resources
// └── target/                      <- Build output (auto-generated)

// pom.xml example (key parts):
/*
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         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-project</artifactId>
    <version>1.0.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>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10.1</version>
        </dependency>
    </dependencies>
</project>
*/

public class MavenProjectDemo {
    public static void main(String[] args) {
        // Key Maven commands:
        // mvn clean          - Delete target folder
        // mvn compile        - Compile source code
        // mvn test           - Run tests
        // mvn package        - Package as JAR/WAR
        // mvn install        - Install to local repository
        // mvn clean package  - Clean + package (most common)

        // Maven lifecycle:
        // validate -> compile -> test -> package -> verify -> install -> deploy

        System.out.println("Maven project structure understood!");
        System.out.println("Dependencies are declared in <dependencies> of pom.xml.");
    }
}

Gradle Project Structure and build.gradle

Gradle is a modern build tool based on Groovy/Kotlin DSL, offering more conciseness and flexibility.

// Gradle project structure:
// my-project/
// ├── build.gradle(.kts)            <- Build script (core)
// ├── settings.gradle(.kts)         <- Project settings
// ├── gradle/
// │   └── wrapper/
// │       ├── gradle-wrapper.jar    <- Gradle wrapper
// │       └── gradle-wrapper.properties
// ├── gradlew / gradlew.bat        <- Wrapper execution scripts
// ├── src/
// │   ├── main/java/               <- Source (same as Maven)
// │   ├── main/resources/
// │   ├── test/java/
// │   └── test/resources/
// └── build/                        <- Build output

// build.gradle.kts (Kotlin DSL) example:
/*
plugins {
    java
    application
}

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

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.google.code.gson:gson:2.10.1")
    implementation("org.slf4j:slf4j-api:2.0.9")

    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

application {
    mainClass.set("com.example.App")
}

tasks.test {
    useJUnitPlatform()
}
*/

public class GradleProjectDemo {
    public static void main(String[] args) {
        // Key Gradle commands:
        // ./gradlew build         - Full build
        // ./gradlew clean         - Delete build folder
        // ./gradlew test          - Run tests
        // ./gradlew run           - Run application
        // ./gradlew dependencies  - View dependency tree
        // ./gradlew tasks         - List available tasks

        System.out.println("Gradle is faster and more concise than Maven!");
        System.out.println("Using the ./gradlew wrapper allows builds without Gradle installation.");
    }
}

Dependency Management

How to add and manage external libraries in your project.

// Dependency scope comparison:
//
// Maven           | Gradle              | Description
// compile (default) | implementation     | Needed at compile + runtime
// provided        | compileOnly          | Needed only at compile (provided at runtime)
// runtime         | runtimeOnly          | Needed only at runtime
// test            | testImplementation   | Needed only for testing
// -               | api                  | Exposes dependency externally (for libraries)

// Commonly used dependencies (Gradle Kotlin DSL):
/*
dependencies {
    // JSON processing
    implementation("com.google.code.gson:gson:2.10.1")
    implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2")

    // Logging
    implementation("ch.qos.logback:logback-classic:1.4.11")

    // HTTP client
    implementation("com.squareup.okhttp3:okhttp:4.12.0")

    // Database
    implementation("com.h2database:h2:2.2.224")

    // Lombok (code generation)
    compileOnly("org.projectlombok:lombok:1.18.30")
    annotationProcessor("org.projectlombok:lombok:1.18.30")

    // Testing
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
    testImplementation("org.assertj:assertj-core:3.24.2")
    testImplementation("org.mockito:mockito-core:5.7.0")
}
*/

import java.util.Map;

public class DependencyManagement {
    public static void main(String[] args) {
        // Dependency conflict resolution:
        // - Maven: exclude with <exclusions>, unify versions with <dependencyManagement>
        // - Gradle: exclude with exclude, force versions with constraints

        // BOM (Bill of Materials): manage related library versions together
        // Spring Boot BOM, JUnit BOM, etc.

        Map<String, String> comparison = Map.of(
            "Config file", "Maven: XML / Gradle: Groovy/Kotlin",
            "Build speed", "Gradle is 2-10x faster (caching/incremental builds)",
            "Flexibility", "Gradle is more flexible (build logic as code)",
            "Learning curve", "Maven is simpler (convention-based)",
            "Adoption", "Spring Boot, Android recommend Gradle"
        );

        System.out.println("=== Maven vs Gradle Comparison ===");
        comparison.forEach((key, value) ->
            System.out.printf("%-15s: %s%n", key, value));
    }
}

Multi-Module Projects

A structure for splitting large projects into multiple modules.

// Multi-module Gradle project structure:
// my-app/
// ├── settings.gradle.kts
// │   -> include("app-core", "app-api", "app-web")
// ├── build.gradle.kts (root: common settings)
// ├── app-core/
// │   ├── build.gradle.kts
// │   └── src/main/java/...
// ├── app-api/
// │   ├── build.gradle.kts
// │   └── src/main/java/...
// └── app-web/
//     ├── build.gradle.kts
//     └── src/main/java/...

// Root build.gradle.kts:
/*
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.test {
        useJUnitPlatform()
    }
}
*/

// app-api/build.gradle.kts:
/*
dependencies {
    implementation(project(":app-core"))  // Depend on another module
    implementation("org.springframework.boot:spring-boot-starter-web:3.2.0")
}
*/

public class MultiModuleProject {
    public static void main(String[] args) {
        System.out.println("Advantages of multi-module projects:");
        System.out.println("1. Separation of concerns (core, api, web)");
        System.out.println("2. Independent build and testing");
        System.out.println("3. Clear dependency management");
        System.out.println("4. Rebuild only changed modules (speed)");
        System.out.println("5. Enables independent team development");
    }
}

Today’s Exercises

  1. Create a Gradle Project: Create a Gradle Java project with ./gradlew init --type java-application or manually, add the Gson dependency, and write a JSON parsing program. Run it with ./gradlew run.

  2. Maven to Gradle Conversion: Convert a given Maven pom.xml to a Gradle build.gradle.kts. Maintain the same dependencies, plugins, and settings.

  3. Custom Gradle Task: Create a custom task in build.gradle.kts. Write a task that outputs the number of source files, total lines of code, and dependency list to a text file when you run ./gradlew generateReport.

Was this article helpful?