Kompilasi manual dan pengemasan JAR di dua chapter sebelumnya menunjukkan pola kerja yang berulang: bersihkan output, kompilasi, uji, kemas, ulangi. Maven — build tool dari Apache yang lahir tahun 2004 — mengotomatiskan seluruh rangkaian itu dari satu berkas deskripsi proyek bernama pom.xml. Filosofi kerjanya, convention over configuration, membuat Maven mengasumsikan struktur direktori dan urutan langkah build yang standar sehingga kita cukup mendeskripsikan pengecualian. Pada chapter ini kita akan membedah anatomi POM, koordinat GAV yang menjadi identitas setiap artifact, serta bagaimana Maven menemukan dependency lewat repositori lokal dan Maven Central.

Apa itu Maven #

Maven adalah tiga hal sekaligus. Pertama, build tool: Maven menjalankan kompilasi, pengujian, dan packaging melalui rangkaian fase yang tetap urutannya. Kedua, dependency manager: Maven mengunduh library eksternal beserta dependency-nya yang transitif, lalu menyusun classpath secara otomatis. Ketiga, project model: POM mendeskripsikan proyek — nama, versi, packaging, dependensi — dalam format XML yang dapat dibaca alat lain, termasuk IDE.

Karena seluruh konfigurasi hidup di pom.xml, anggota tim baru tidak perlu menyalin skrip build dari rekan kerjanya; cukup menjalankan perintah yang sama pada berkas yang sama dan Maven akan membangun proyek dengan perilaku identik.

Convention over Configuration #

Build tool generatif lain di masa lalu menuntut kita menulis skrip langkah demi langkah. Maven membalik pendekatannya: Maven sudah menetapkan di mana kode sumber berada (src/main/java), di mana kode uji berada (src/test/java), di mana output ditulis (target/), dan urutan fase build dari validate sampai deploy. Selama proyek mengikuti konvensi tersebut, tidak ada satu baris konfigurasi pun yang perlu ditulis untuk hal-hal tersebut.

Konfigurasi baru diperlukan saat menyimpang dari konvensi — misalnya mengubah versi Java target atau menambah dependency. Hasilnya, POM proyek biasa hanya berisi belasan baris yang semuanya bermakna, bukan ratusan baris instruksi mekanis.

POM sebagai Pusat Kendali #

Berkas pom.xml berikut adalah deskripsi minimum sebuah aplikasi Java bernama aplikasi-gudang:

xml pom.xml minimal
<?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.toko.gudang</groupId>
    <artifactId>aplikasi-gudang</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.release>21</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Mari kita bedah elemen-elemennya:

  1. <modelVersion>: versi model POM yang dipakai; nilainya 4.0.0 untuk seluruh Maven modern.
  2. <groupId>: identitas organisasi pembuat, lazim berupa domain terbalik seperti com.toko.gudang.
  3. <artifactId>: nama proyek atau modul; hasil build biasanya bernama artifactId-version.jar.
  4. <version>: versi artifact saat ini, mengikuti pola MAJOR.MINOR.PATCH.
  5. <packaging>: bentuk hasil akhir — jar untuk library/aplikasi, war untuk aplikasi web, pom untuk agregator multi-modul.
  6. <properties>: variabel konfigurasi; maven.compiler.release menyetel opsi --release compiler, dan sourceEncoding memastikan berkas sumber dibaca sebagai UTF-8.

Dengan POM sekecil itu pun, Maven sudah tahu harus berbuat apa. Perintah mvn clean package membersihkan direktori target/, mengompilasi seluruh src/main/java, menjalankan pengujian dari src/test/java, lalu menghasilkan target/aplikasi-gudang-1.0.0.jar — semuanya dari konvensi, tanpa satu instruksi build pun yang kita tulis.

Koordinat GAV #

Setiap artifact di dunia Maven diidentifikasi oleh tiga bagian yang disebut koordinat GAV: groupId, artifactId, dan version. Format penulisannya adalah groupId:artifactId:version — misalnya org.apache.commons:commons-lang3:3.14.0. Program kecil berikut memecah koordinat GAV dan menurunkan lokasi penyimpanannya di repositori:

public class KoordinatGav {
    public static void main(String[] args) {
        String[] daftarGav = {
            "org.apache.commons:commons-lang3:3.14.0",
            "com.toko.gudang:aplikasi-gudang:1.0.0",
            "junit:junit:4.13.2"
        };

        for (String gav : daftarGav) {
            String[] bagian = gav.split(":");
            System.out.printf("GAV        : %s%n", gav);
            System.out.printf("groupId    : %s%n", bagian[0]);
            System.out.printf("artifactId : %s%n", bagian[1]);
            System.out.printf("version    : %s%n", bagian[2]);
            System.out.printf("path repo  : %s%n", kePathRepositori(bagian));
            System.out.println();
        }
    }

    /** Maven menyimpan artifact dengan pola groupId(dots->slash)/artifactId/version/ */
    private static String kePathRepositori(String[] bagian) {
        String grup = bagian[0].replace('.', '/');
        return grup + "/" + bagian[1] + "/" + bagian[2]
                + "/" + bagian[1] + "-" + bagian[2] + ".jar";
    }
}

Output yang Dihasilkan:

text
GAV        : org.apache.commons:commons-lang3:3.14.0
groupId    : org.apache.commons
artifactId : commons-lang3
version    : 3.14.0
path repo  : org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar

GAV        : com.toko.gudang:aplikasi-gudang:1.0.0
groupId    : com.toko.gudang
artifactId : aplikasi-gudang
version    : 1.0.0
path repo  : com/toko/gudang/aplikasi-gudang/1.0.0/aplikasi-gudang-1.0.0.jar

GAV        : junit:junit:4.13.2
groupId    : junit
artifactId : junit
version    : 4.13.2
path repo  : junit/junit/4.13.2/junit-4.13.2.jar

Tiga hal terlihat dari output di atas:

  1. Baris GAV sampai version: satu koordinat terurai menjadi tiga field — inilah cara Maven (dan pengguna Maven Central) menyebut artifact tanpa ambigu.
  2. Baris path repo: setiap titik pada groupId menjadi pemisah direktori, diikuti artifactId/version, sehingga org.apache.commons:commons-lang3:3.14.0 tersimpan di org/apache/commons/commons-lang3/3.14.0/.
  3. Nama berkas: polanya artifactId-version.jar, misalnya aplikasi-gudang-1.0.0.jar — alasan Maven dapat menebak nama berkas hasil build dari POM.

Super POM dan POM Efektif #

POM Anda tidak pernah berdiri sendiri. Setiap POM mewarisi super POM — definisi bawaan Maven yang memuat repositori Central, struktur direktori standar, dan goal plugin inti. Gabungan super POM, POM proyek, dan (bila ada) POM induk disebut effective POM. Maven selalu membaca effective POM inilah, bukan berkas pom.xml mentah Anda.

Konsekuensinya praktis: mvn help:effective-pom menampilkan POM final yang benar-benar dipakai — alat diagnosis utama ketika perilaku build tidak sesuai dugaan. Pada proyek multi-modul, POM induk (packaging bernilai pom) menyimpan konfigurasi bersama seperti versi Java dan daftar dependency, lalu setiap modul mewarisinya dan hanya menambahkan bagian khas modul.

Repositori Lokal dan Maven Central #

Saat Maven menemukan deklarasi dependency, Maven mencari berkas JAR dalam urutan tetap: repositori lokal di ~/.m2/repository lebih dulu, lalu repositori remote seperti Maven Central (repo.maven.apache.org). Berkas yang ditemukan di remote diunduh sekali dan disimpan ke repositori lokal — build berikutnya membaca dari disk sehingga cepat dan tetap berjalan saat jaringan tidak tersedia. Peta prosesnya:

Path penyimpanan lokal mengikuti pola pada program KoordinatGav di atas, sehingga kita bisa menelusuri isi ~/.m2/repository secara manual untuk memastikan versi mana yang sudah ada di mesin.

Filosofi convention over configuration, koordinat GAV, dan repositori adalah tiga fondasi Maven. Chapter berikutnya menelusuri struktur direktori standar yang diisyaratkan konvensi tersebut — dari src/main/java hingga target/ — beserta pemetaan groupId ke struktur package.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

KoordinatGav.java

Unduh berkas
java
public class KoordinatGav {
    public static void main(String[] args) {
        String[] daftarGav = {
            "org.apache.commons:commons-lang3:3.14.0",
            "com.toko.gudang:aplikasi-gudang:1.0.0",
            "junit:junit:4.13.2"
        };

        for (String gav : daftarGav) {
            String[] bagian = gav.split(":");
            System.out.printf("GAV        : %s%n", gav);
            System.out.printf("groupId    : %s%n", bagian[0]);
            System.out.printf("artifactId : %s%n", bagian[1]);
            System.out.printf("version    : %s%n", bagian[2]);
            System.out.printf("path repo  : %s%n", kePathRepositori(bagian));
            System.out.println();
        }
    }

    /** Maven menyimpan artifact dengan pola groupId(dots->slash)/artifactId/version/ */
    private static String kePathRepositori(String[] bagian) {
        String grup = bagian[0].replace('.', '/');
        return grup + "/" + bagian[1] + "/" + bagian[2]
                + "/" + bagian[1] + "-" + bagian[2] + ".jar";
    }
}