Build Tools

Build Tools #

Bayangkan kamu harus mengompilasi 50 file Java satu per satu dari command line, lalu mengunduh manual setiap library yang dibutuhkan, lalu mengemasnya menjadi satu file JAR dengan urutan classpath yang benar. Itu pekerjaan yang membosankan, rawan salah, dan tidak bisa diulang secara konsisten antar mesin. Build tool hadir untuk mengotomasi semua itu. Ia mengurus kompilasi, manajemen dependency, pengujian, dan pengemasan — kamu cukup mendefinisikan apa yang diinginkan, build tool yang mengerjakan bagaimana-nya. Di ekosistem Java, ada tiga build tool utama: Maven, Gradle, dan Ant. Artikel ini membahas cara kerja, konfigurasi, struktur proyek, perintah penting, dan panduan memilih masing-masing.

Gambaran Umum #

Setiap build tool punya filosofi dan pendekatan berbeda:

AspekMavenGradleAnt
Konfigurasipom.xml (XML)build.gradle (Groovy/Kotlin)build.xml (XML)
FilosofiConvention over configurationFleksibel, berbasis taskManual dan eksplisit
Manajemen dependency✓ Otomatis✓ Otomatis✗ Manual
Kecepatan buildSedangCepat (incremental + cache)Sedang
Kurva belajarSedangSedang-tinggiRendah
EkosistemSangat luasLuasTerbatas
Digunakan diSpring Boot, enterpriseAndroid, proyek modernProyek legacy
flowchart LR
    A["Kode Sumber\n(.java)"] --> B["Build Tool"]
    C["Dependencies\n(JAR)"] --> B
    D["Resource\n(config, assets)"] --> B
    B --> E["Compile\n(.class)"]
    E --> F["Test"]
    F --> G["Package\n(.jar / .war)"]
    G --> H["Deploy"]

Apache Maven #

Maven adalah build tool paling populer di ekosistem Java enterprise. Filosofi utamanya adalah convention over configuration — selama kamu mengikuti struktur direktori standar Maven, hampir tidak ada konfigurasi yang perlu ditulis. Maven juga menjadi standar de facto untuk publikasi library ke Maven Central, repositori publik terbesar untuk ekosistem JVM.

Inisiasi Proyek #

# Buat proyek baru via command line
mvn archetype:generate \
  -DgroupId=com.example \
  -DartifactId=nama-proyek \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DinteractiveMode=false

# Penjelasan parameter:
# groupId     → identitas organisasi/domain terbalik (com.example)
# artifactId  → nama proyek (nama-proyek)
# archetype   → template proyek — quickstart adalah template Java paling dasar

Hasilnya adalah proyek siap pakai dengan struktur direktori standar dan pom.xml yang sudah terisi.

Struktur Direktori #

nama-proyek/
├── pom.xml                          ← file konfigurasi utama
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/example/
    │   │       └── App.java         ← kode sumber utama
    │   └── resources/
    │       └── application.properties
    └── test/
        ├── java/
        │   └── com/example/
        │       └── AppTest.java     ← kode pengujian
        └── resources/
            └── test-config.properties

Direktori target/ akan dibuat otomatis saat build dijalankan — berisi .class, JAR hasil build, dan laporan test.

Anatomi pom.xml #

pom.xml (Project Object Model) adalah jantung proyek Maven. Semua konfigurasi — identitas proyek, dependency, plugin, dan proses build — didefinisikan di sini.

<?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>

    <!-- Identitas proyek -->
    <groupId>com.example</groupId>
    <artifactId>nama-proyek</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!-- Properti global -->
    <properties>
        <java.version>21</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- Dependency yang dibutuhkan proyek -->
    <dependencies>

        <!-- Library utama -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>33.0.0-jre</version>
        </dependency>

        <!-- Library hanya untuk testing — tidak ikut ke JAR produksi -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <!-- Plugin build -->
    <build>
        <plugins>
            <!-- Plugin untuk menjalankan unit test -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.1.2</version>
            </plugin>
        </plugins>
    </build>

</project>

Dependency Scope #

Scope menentukan kapan dependency tersedia dan apakah ia ikut dalam hasil build akhir.

ScopeTersedia saatMasuk ke JAR
compile (default)Kompilasi + runtime + test
testTest saja
providedKompilasi + test (disediakan server)
runtimeRuntime + test (tidak saat kompilasi)
optionalOpsional untuk pengguna library ini

Perintah Maven Penting #

# Kompilasi kode sumber
mvn compile

# Jalankan semua unit test
mvn test

# Buat file JAR (termasuk compile dan test)
mvn package

# Install ke local repository (~/.m2)
mvn install

# Bersihkan direktori target/
mvn clean

# Kombinasi paling sering dipakai
mvn clean package

# Lewati test (untuk build cepat, tidak disarankan di CI)
mvn clean package -DskipTests

# Tampilkan dependency tree — berguna untuk debug konflik versi
mvn dependency:tree

# Update versi dependency ke yang terbaru
mvn versions:display-dependency-updates

Maven Lifecycle #

Maven punya tiga lifecycle bawaan, masing-masing terdiri dari fase-fase yang dijalankan berurutan. Saat kamu menjalankan mvn package, semua fase sebelumnya (validate, compile, test) otomatis dijalankan juga.

flowchart LR
    A[validate] --> B[compile] --> C[test] --> D[package] --> E[verify] --> F[install] --> G[deploy]

Gradle #

Gradle adalah build tool modern yang menggabungkan kelebihan Maven (manajemen dependency otomatis, repositori publik) dengan fleksibilitas Ant (logika build bisa ditulis sebagai kode nyata, bukan hanya XML). Gradle menggunakan Groovy atau Kotlin DSL untuk konfigurasi — ini berarti konfigurasi build adalah kode yang sesungguhnya, bukan sekadar deklarasi XML.

Keunggulan teknis utama Gradle adalah incremental build dan build cache — Gradle hanya mengompilasi ulang file yang benar-benar berubah, dan bisa menggunakan cache dari build sebelumnya. Ini membuat build Gradle jauh lebih cepat daripada Maven di proyek besar.

Inisiasi Proyek #

# Inisiasi proyek interaktif
gradle init

# Gradle akan menanyakan:
# - Tipe proyek: application, library, Gradle plugin
# - Bahasa: Java, Kotlin, Groovy, Scala
# - DSL build script: Groovy atau Kotlin
# - Nama proyek dan package

# Hasil: proyek siap pakai dengan Gradle Wrapper (./gradlew)

Gradle Wrapper (./gradlew) adalah script yang mengunduh dan menjalankan versi Gradle yang spesifik tanpa perlu instalasi Gradle di mesin. Ini menjamin semua developer dan CI/CD memakai versi yang sama.

Struktur Direktori #

nama-proyek/
├── build.gradle          ← konfigurasi build (Groovy DSL)
├── build.gradle.kts      ← konfigurasi build (Kotlin DSL) — salah satu saja
├── settings.gradle       ← nama proyek dan konfigurasi multi-project
├── gradlew               ← Gradle Wrapper script (Linux/Mac)
├── gradlew.bat           ← Gradle Wrapper script (Windows)
├── gradle/
│   └── wrapper/
│       └── gradle-wrapper.properties  ← versi Gradle yang dipakai
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/example/
    │   │       └── App.java
    │   └── resources/
    └── test/
        ├── java/
        │   └── com/example/
        │       └── AppTest.java
        └── resources/

Anatomi build.gradle (Groovy DSL) #

// Deklarasi plugin — 'java' menambahkan task compile, test, jar, dll.
plugins {
    id 'java'
    id 'application'
}

// Identitas proyek
group = 'com.example'
version = '1.0.0'

// Konfigurasi Java
java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}

// Repositori untuk mengunduh dependency
repositories {
    mavenCentral() // Maven Central — repositori publik utama
}

// Dependency proyek
dependencies {
    // Dependency utama (compile + runtime)
    implementation 'com.google.guava:guava:33.0.0-jre'

    // Dependency hanya untuk test
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

// Konfigurasi task test
test {
    useJUnitPlatform()
}

// Main class untuk task 'run'
application {
    mainClass = 'com.example.App'
}

Anatomi build.gradle.kts (Kotlin DSL) #

Kotlin DSL semakin populer karena memberikan type safety dan autocomplete yang lebih baik di IDE.

plugins {
    java
    application
}

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

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

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.google.guava:guava:33.0.0-jre")
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.test {
    useJUnitPlatform()
}

application {
    mainClass = "com.example.App"
}

Konfigurasi Dependency Scope #

Gradle menggunakan nama konfigurasi yang berbeda dari Maven:

GradleSetara Maven scopeKeterangan
implementationcompileDependency utama, tidak bocor ke konsumer
apicompileDependency utama, bocor ke konsumer (untuk library)
testImplementationtestHanya untuk test
compileOnlyprovidedSaat kompilasi saja, tidak runtime
runtimeOnlyruntimeRuntime saja, tidak saat kompilasi

Perintah Gradle Penting #

# Gunakan Gradle Wrapper (selalu gunakan ini, bukan gradle langsung)
./gradlew <task>    # Linux/Mac
gradlew.bat <task>  # Windows

# Task-task utama
./gradlew build          # compile + test + jar
./gradlew test           # jalankan semua test
./gradlew run            # jalankan main class (butuh plugin 'application')
./gradlew jar            # buat file JAR tanpa test
./gradlew clean          # hapus direktori build/
./gradlew clean build    # bersih lalu build ulang

# Lewati test
./gradlew build -x test

# Tampilkan semua task yang tersedia
./gradlew tasks

# Tampilkan dependency tree
./gradlew dependencies

# Tampilkan dependency untuk konfigurasi tertentu
./gradlew dependencies --configuration compileClasspath

# Build dengan informasi detail
./gradlew build --info

# Build dengan scan performa (perlu koneksi internet)
./gradlew build --scan

Custom Task #

Salah satu kelebihan Gradle adalah kemampuan mendefinisikan task kustom langsung di build.gradle.

// Task kustom sederhana
tasks.register('sapa') {
    doLast {
        println "Halo dari Gradle!"
    }
}

// Task yang bergantung pada task lain
tasks.register('deployJar', Copy) {
    dependsOn jar
    from jar.archiveFile
    into '/opt/app/deploy/'
}

// Jalankan: ./gradlew sapa

Apache Ant #

Ant adalah build tool tertua dari ketiganya — ada jauh sebelum Maven dan Gradle. Berbeda dari keduanya, Ant tidak punya opini tentang bagaimana proyek harus distrukturkan dan tidak mengurus manajemen dependency secara otomatis. Kamu mendefinisikan setiap langkah build secara eksplisit dalam build.xml. Fleksibilitas ini berguna di skenario tertentu, tapi juga berarti lebih banyak pekerjaan manual.

Struktur Direktori #

Ant tidak memaksa struktur tertentu, tapi konvensi yang paling umum adalah:

nama-proyek/
├── build.xml             ← script build utama
├── src/
│   └── com/example/
│       └── App.java
├── test/
│   └── com/example/
│       └── AppTest.java
├── lib/
│   └── junit-5.10.0.jar  ← dependency disimpan manual
├── build/
│   ├── classes/          ← hasil kompilasi
│   └── test-classes/
└── dist/
    └── nama-proyek.jar   ← hasil akhir build

Anatomi build.xml #

<?xml version="1.0" encoding="UTF-8"?>
<project name="NamaProyek" default="jar" basedir=".">

    <!-- Properti — variabel yang bisa dipakai di seluruh file -->
    <property name="src.dir"          value="src"/>
    <property name="test.dir"         value="test"/>
    <property name="lib.dir"          value="lib"/>
    <property name="build.dir"        value="build"/>
    <property name="build.classes"    value="${build.dir}/classes"/>
    <property name="build.test"       value="${build.dir}/test-classes"/>
    <property name="dist.dir"         value="dist"/>
    <property name="jar.name"         value="nama-proyek.jar"/>

    <!-- Classpath: library yang dibutuhkan -->
    <path id="compile.classpath">
        <fileset dir="${lib.dir}" includes="*.jar"/>
    </path>

    <path id="test.classpath">
        <path refid="compile.classpath"/>
        <pathelement location="${build.classes}"/>
        <pathelement location="${build.test}"/>
    </path>

    <!-- Target: init — buat direktori yang diperlukan -->
    <target name="init">
        <mkdir dir="${build.classes}"/>
        <mkdir dir="${build.test}"/>
        <mkdir dir="${dist.dir}"/>
    </target>

    <!-- Target: compile — kompilasi kode sumber -->
    <target name="compile" depends="init">
        <javac srcdir="${src.dir}"
               destdir="${build.classes}"
               classpathref="compile.classpath"
               includeantruntime="false"
               source="21" target="21"
               encoding="UTF-8"/>
    </target>

    <!-- Target: compile-test — kompilasi kode test -->
    <target name="compile-test" depends="compile">
        <javac srcdir="${test.dir}"
               destdir="${build.test}"
               classpathref="test.classpath"
               includeantruntime="false"
               source="21" target="21"/>
    </target>

    <!-- Target: test — jalankan unit test -->
    <target name="test" depends="compile-test">
        <junit printsummary="yes" haltonfailure="yes">
            <classpath refid="test.classpath"/>
            <batchtest>
                <fileset dir="${build.test}" includes="**/*Test.class"/>
            </batchtest>
        </junit>
    </target>

    <!-- Target: jar — buat file JAR -->
    <target name="jar" depends="compile">
        <jar destfile="${dist.dir}/${jar.name}"
             basedir="${build.classes}">
            <manifest>
                <attribute name="Main-Class" value="com.example.App"/>
            </manifest>
        </jar>
        <echo>JAR dibuat: ${dist.dir}/${jar.name}</echo>
    </target>

    <!-- Target: clean — hapus hasil build -->
    <target name="clean">
        <delete dir="${build.dir}"/>
        <delete dir="${dist.dir}"/>
    </target>

</project>

Menjalankan Target Ant #

# Jalankan target default (sesuai atribut default di <project>)
ant

# Jalankan target tertentu
ant compile
ant test
ant jar
ant clean

# Jalankan beberapa target berurutan
ant clean jar

# Gunakan file build yang berbeda
ant -f build-prod.xml jar

# Tampilkan semua target yang tersedia
ant -projecthelp

Ivy — Manajemen Dependency untuk Ant #

Ant sendiri tidak punya manajemen dependency. Untuk itu, bisa ditambahkan Apache Ivy — library terpisah yang memberikan kemampuan unduh dependency otomatis ke proyek Ant.

<!-- Tambahkan ke build.xml -->
<taskdef resource="org/apache/ivy/ant/antlib.xml"
         uri="antlib:org.apache.ivy.ant"
         classpath="lib/ivy.jar"/>

<!-- Resolve dependency berdasarkan ivy.xml -->
<target name="resolve">
    <ivy:retrieve/>
</target>
<!-- ivy.xml: daftar dependency, mirip pom.xml Maven -->
<ivy-module version="2.0">
    <info organisation="com.example" module="nama-proyek"/>
    <dependencies>
        <dependency org="com.google.guava" name="guava" rev="33.0.0-jre"/>
        <dependency org="org.junit.jupiter" name="junit-jupiter" rev="5.10.0" conf="test->default"/>
    </dependencies>
</ivy-module>

Perbandingan File Konfigurasi #

Untuk menambahkan dependency yang sama — misalnya Guava — berikut cara penulisannya di ketiga build tool:

Menambah Dependency Guava #

Maven (pom.xml):

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.0.0-jre</version>
</dependency>

Gradle Groovy (build.gradle):

implementation 'com.google.guava:guava:33.0.0-jre'

Gradle Kotlin (build.gradle.kts):

implementation("com.google.guava:guava:33.0.0-jre")

Ant + Ivy (ivy.xml):

<dependency org="com.google.guava" name="guava" rev="33.0.0-jre"/>

Ant tanpa Ivy:

Unduh guava-33.0.0-jre.jar secara manual → simpan ke lib/ → referensikan di classpath

Integrasi dengan IDE #

IntelliJ IDEA #

IntelliJ mendeteksi build tool secara otomatis saat membuka proyek. Kamu bisa langsung import dan IDE akan mengunduh dependency serta mengkonfigurasi classpath tanpa langkah tambahan.

Maven → buka folder proyek yang berisi pom.xml → Import as Maven Project
Gradle → buka folder proyek yang berisi build.gradle → Import as Gradle Project
Ant   → buka folder proyek → tambahkan build.xml lewat menu Ant tool window

VS Code #

# Install Extension Pack for Java (mencakup Maven dan Gradle support)
# Maven: gunakan "Maven for Java" extension
# Gradle: gunakan "Gradle for Java" extension

Kapan Menggunakan Tiap Build Tool #

Gunakan MAVEN jika:
  ✓ Proyek enterprise Java atau Spring Boot
  ✓ Tim sudah familiar dengan Maven dan ekosistemnya
  ✓ Butuh konvensi standar yang ketat dan mudah dipahami semua orang
  ✓ Akan mempublikasikan library ke Maven Central
  ✓ Multi-module project dengan struktur hierarki sederhana

Gunakan GRADLE jika:
  ✓ Proyek Android (Gradle adalah satu-satunya opsi resmi)
  ✓ Butuh build yang cepat — incremental build dan cache sangat membantu
  ✓ Logika build kompleks yang tidak bisa diekspresikan dengan XML saja
  ✓ Multi-project build dengan dependency antar modul yang rumit
  ✓ Tim nyaman menulis konfigurasi sebagai kode (Groovy/Kotlin)

Gunakan ANT jika:
  ✓ Memaintain proyek lama yang sudah pakai Ant
  ✓ Butuh kontrol penuh atas setiap langkah build
  ✓ Integrasi dengan toolchain non-standar yang tidak didukung Maven/Gradle
  ✗ Hindari untuk proyek baru — pilih Maven atau Gradle

Pilihan default untuk proyek baru:
  → Maven jika tim enterprise dan butuh kesederhanaan
  → Gradle jika butuh performa atau fleksibilitas tinggi

Ringkasan #

  • Maven menggunakan pom.xml (XML) dengan filosofi convention over configuration. Struktur direktori src/main/java dan src/test/java sudah menjadi standar industri Java. Cocok untuk proyek enterprise dan Spring Boot.
  • Gradle menggunakan build.gradle (Groovy atau Kotlin DSL) yang lebih ringkas dan ekspresif. Incremental build dan build cache membuatnya jauh lebih cepat dari Maven di proyek besar. Wajib dipakai untuk Android.
  • Ant menggunakan build.xml dan memberikan kontrol penuh tapi tanpa manajemen dependency bawaan. Masih relevan untuk proyek legacy dan skenario build yang sangat kustom.
  • Gradle Wrapper (./gradlew) adalah cara terbaik menjalankan Gradle — memastikan semua developer dan CI/CD memakai versi Gradle yang sama tanpa instalasi manual.
  • Dependency scope penting untuk efisiensi — tandai library testing dengan scope test (Maven) atau testImplementation (Gradle) agar tidak ikut ke build produksi.
  • mvn clean package dan ./gradlew clean build adalah perintah build bersih yang paling sering dipakai — hapus hasil lama, kompilasi, test, lalu kemas.
  • Maven Lifecycle berjalan berurutan — menjalankan mvn package otomatis menjalankan validate, compile, dan test di depannya.
  • Ant tanpa Ivy berarti download dependency manual — pertimbangkan tambahkan Ivy atau migrasi ke Maven/Gradle jika manajemen dependency menjadi beban.

← Sebelumnya: Regex   Berikutnya: Multi Threading →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact