Sepanjang section ini kita menjalankan alat langsung dari kode sumber — nyaman saat pengembangan, tetapi bukan bentuk yang bisa diserahkan ke pengguna: mesin sasaran mungkin tidak punya JDK. Packaging menutup jarak itu lewat tangga empat anak: kelas hasil kompilasi dibungkus JAR, JAR diberi titik masuk lewat manifest, aplikasi dirakit bersama runtime minimal menjadi image jlink, lalu dibungkus pemasang lewat jpackage. Chapter penutup section ini menaiki tangga itu dengan satu alat kecil yang sama.
Dari Kode Sumber ke JAR #
Alat paketan kita sengaja kecil: sapa menyapa satu nama dan melaporkan versinya. Seluruh konvensi CLI dari chapter Utilitas Command Line tetap berlaku — keluaran data ke stdout, keluhan ke stderr, exit code sebagai kontrak:
public class Sapa {
static final String VERSI = "1.0";
public static void main(String[] args) {
if (args.length == 1 && args[0].equals("--versi")) {
System.out.println("sapa " + VERSI);
return;
}
if (args.length != 1) {
System.err.println("Pemakaian: sapa NAMA | sapa --versi");
System.exit(2);
}
System.out.println("Halo, " + args[0] + "!");
}
}Output yang Dihasilkan:
Halo, Budi!Pemakaian yang salah tetap ditolak: tanpa argumen, program mencetak Pemakaian: sapa NAMA | sapa --versi ke stderr lalu keluar dengan exit code 2 — kontrak yang terbawa utuh ke semua bentuk kemasan berikutnya:
public class Sapa {
static final String VERSI = "1.0";
public static void main(String[] args) {
if (args.length == 1 && args[0].equals("--versi")) {
System.out.println("sapa " + VERSI);
return;
}
if (args.length != 1) {
System.err.println("Pemakaian: sapa NAMA | sapa --versi");
System.exit(2);
}
System.out.println("Halo, " + args[0] + "!");
}
}Sesi berikut dikutip dari eksekusi sungguhan dengan JDK 25:
$ javac -d kelas Sapa.java
$ jar --create --file sapa.jar --main-class Sapa -C kelas .
$ jar --list --file sapa.jar
META-INF/
META-INF/MANIFEST.MF
Sapa.class
$ java -jar sapa.jar Budi
Halo, Budi!
$ java -jar sapa.jar --versi
sapa 1.0
$ java -cp sapa.jar Sapa Siti
Halo, Siti!Mari kita telaah perintah-perintahnya:
- Baris
javac -d kelas Sapa.java: compiler menaruhSapa.classdi direktorikelas/— berkas bytecode inilah yang dibagikan, bukan sumbernya. - Baris
jar --create --file sapa.jar --main-class Sapa -C kelas .: alatjarmembungkus isikelas/menjadi satu arsip;-C kelas .berarti “ambil semuanya dari dalam direktori kelas”, dan--main-class Sapamenuliskan atributMain-Classke manifest. - Hasil
jar --list: JAR hanyalah arsip zip berisi berkas.classplus dua entri khusus: direktoriMETA-INF/danMANIFEST.MFdi dalamnya. - Manifest hasilnya berisi tiga baris —
Manifest-Version: 1.0,Created-By: 25.0.4.1 (Eclipse Adoptium), danMain-Class: Sapa; baris terakhir itulah yang dibacajava -jar. - Baris
java -jar sapa.jar Budi: peluncur membaca manifest, menjalankanSapa.main, lalu meneruskanBudisebagai argumen — pengguna tidak perlu tahu nama class di dalam arsip. - Baris
java -cp sapa.jar Sapa Siti: jalur tanpa manifest — classpath menyatakan letak kelas dan nama class ditulis eksplisit; berguna saat satu arsip berisi beberapa program.
Image Runtime dengan jlink #
JAR menghilangkan langkah kompilasi, tetapi masih menuntut java yang tepat terpasang di mesin pengguna. jlink melangkah lebih jauh: merakit aplikasi bersama bagian JDK yang dibutuhkan menjadi satu direktori image yang berjalan mandiri. Modul menuntut class berada di package bernama, jadi versi modular alat kita diletakkan di com/contoh/sapa/Sapa.java:
package com.contoh.sapa;
public class Sapa {
static final String VERSI = "1.0";
public static void main(String[] args) {
if (args.length == 1 && args[0].equals("--versi")) {
System.out.println("sapa " + VERSI);
return;
}
if (args.length != 1) {
System.err.println("Pemakaian: sapa NAMA | sapa --versi");
System.exit(2);
}
System.out.println("Halo, " + args[0] + "!");
}
}module sapa {
// java.base selalu tersedia secara implisit; tidak ada kebutuhan lain.
}Sesi berikut juga dikutip dari eksekusi sungguhan:
$ javac -d modul src/module-info.java src/com/contoh/sapa/Sapa.java
$ jlink --add-modules sapa --module-path modul --output citra-sapa --launcher sapa=sapa/com.contoh.sapa.Sapa --strip-debug --no-header-files --no-man-pages
$ citra-sapa/bin/sapa Budi
Halo, Budi!
$ citra-sapa/bin/sapa --versi
sapa 1.0
$ citra-sapa/bin/java --list-modules
[email protected]
sapaMari kita telaah flag-flag jlink:
- Flag
--module-path modul: lokasi modul aplikasi hasiljavac. - Flag
--add-modules sapa: modul yang dirakit beserta seluruh dependensinya; karenasapahanya membutuhkanjava.base, image akhirnya berisi dua modul saja — terbukti pada keluaran--list-modules. - Flag
--launcher sapa=sapa/com.contoh.sapa.Sapa: membuat skrip peluncurbin/sapa— pengguna memanggilnya tanpa menyebut class, classpath, ataupun modul. - Flag
--strip-debug --no-header-files --no-man-pages: memangkas simbol debug dan berkas pengiring; image contoh ini berukuran ±56 MB — jauh lebih kecil daripada JDK utuh.
Pembungkus Pemasang dengan jpackage #
Anak tangga terakhir menyerahkan pengalaman pemasangan yang dikenal pengguna akhir — .deb, .rpm, .msi, atau .dmg — lewat jpackage, yang merakit image ala jlink, membungkusnya menjadi paket sistem operasi, dan menambahkan peluncur. Bentuk perintahnya:
jpackage --name sapa --input kelas --main-jar sapa.jar \
--main-class Sapa --type deb --dest paketMembangun paket .deb menuntut utilitas pembungkus Debian (fakeroot, dpkg-deb) di mesin build; .msi menuntut WiX di Windows, .dmg menuntut macOS. Detail flag lainnya ada di referensi akhir chapter.
Memilih Bentuk Distribusi #
| Bentuk | Dibutuhkan pengguna | Cocok untuk |
|---|---|---|
Sapa.java (kode sumber) | JDK 25 | eksperimen, skrip internal |
JAR + classpath (java -cp) | JDK | tim pengembang, beberapa program per arsip |
JAR eksekusabel (java -jar) | JDK/JRE 25+ | distribusi internal, entry cron |
Image jlink | tidak ada — runtime ikut terbawa | server, CLI lintas tim, satu platform |
Pemasang jpackage | tidak ada — ada proses pasang | aplikasi desktop pengguna akhir |
Satu batasan jar: alat bawaan JDK ini tidak menggabungkan dependency ke dalam satu arsip. Untuk pustaka pihak ketiga, build tool yang menyatukannya — Maven Shade atau Gradle Shadow menghasilkan fat jar (JAR berisi semua dependensi) dengan manifest Main-Class yang sama.
Section Scripting dan Automation ditutup di sini: eksperimen cepat di jshell, konvensi CLI, parsing argumen, batch dengan checkpoint, otomasi file system, job terjadwal, dan pengemasan untuk distribusi — satu alur utuh dari pertanyaan kecil menjadi artefak siap pakai. Section berikutnya, Proyek, mengajak memakai seluruh bekal itu untuk membangun aplikasi nyata dari nol sampai siap dibagikan.
Referensi #
- Oracle: jar — Panduan Alat JDK 25
- Oracle: jlink — Panduan Alat JDK 25
- Oracle: jpackage — Panduan Alat JDK 25
- OpenJDK: JEP 330 — Launch Single-File Source-Code Programs
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
Sapa.java
Unduh berkaspublic class Sapa {
static final String VERSI = "1.0";
public static void main(String[] args) {
if (args.length == 1 && args[0].equals("--versi")) {
System.out.println("sapa " + VERSI);
return;
}
if (args.length != 1) {
System.err.println("Pemakaian: sapa NAMA | sapa --versi");
System.exit(2);
}
System.out.println("Halo, " + args[0] + "!");
}
}