← Semua pembelajaran / Blockchain Nol → RWA
Fase 3 · Integrasi Backend Java & PHP

web3j — integrasi Java ke smart contract

web3j adalah pustaka Java paling dipakai luas untuk bicara ke Ethereum. Bagian paling berharga dari web3j bukan sekadar wrapper JSON-RPC — melainkan generator yang mengubah ABI kontrak jadi class Java bertipe.

Sumber asli docs.web3j.io Resmi Rangkuman ~8 menit baca

Intisari

  • Web3j.build(new HttpService(rpcUrl)) adalah titik masuk — satu objek yang merepresentasikan koneksi ke node provider.
  • Credentials.create(privateKey) membungkus private key untuk menandatangani transaksi — hanya untuk kode contoh/testnet, produksi memakai KMS (Fase 4).
  • Perintah web3j generate solidity mengubah ABI + bytecode kontrak jadi class Java bertipe — parameter dan tipe kembalian Solidity terpetakan otomatis ke tipe Java.
  • ContractGasProvider menentukan gas limit dan gas price yang dipakai transaksi — DefaultGasProvider untuk belajar, provider kustom untuk produksi (Fase 5).
  • Semua panggilan kontrak (baca maupun tulis) berbentuk RemoteFunctionCall<T> — objek yang baru benar-benar dieksekusi saat kamu panggil .send().

Dependency

<!-- pom.xml -->
<dependency>
    <groupId>org.web3j</groupId>
    <artifactId>core</artifactId>
    <version>4.14.0</version>
</dependency>

Koneksi

import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;

Web3j web3j = Web3j.build(new HttpService(
    "https://eth-sepolia.g.alchemy.com/v2/API_KEY_KAMU"
));

// Cek koneksi hidup — pola health check paling sederhana
BigInteger blockTerbaru = web3j.ethBlockNumber().send().getBlockNumber();

Generate wrapper Java dari ABI

Menulis manual encoding/decoding ABI untuk setiap panggilan fungsi sangat rawan salah. web3j menyediakan generator yang mengubah ABI (dan opsional bytecode) jadi satu class Java lengkap dengan method bertipe untuk setiap fungsi kontrak:

# Dari hasil kompilasi Solidity (Fase 1): GoldToken.abi + GoldToken.bin
web3j generate solidity \
  -a build/GoldToken.abi -b build/GoldToken.bin \
  -o src/main/java -p com.contoh.kontrak

Hasilnya, class GoldToken.java yang setiap fungsi Solidity-nya jadi method Java — mintGold(...), balanceOf(...), redeemGold(...) — lengkap dengan tipe parameter yang sudah dipetakan (uint256 → BigInteger, address → String, dst).

Memuat kontrak yang sudah ter-deploy

import org.web3j.crypto.Credentials;
import org.web3j.tx.gas.DefaultGasProvider;

Credentials kredensial = Credentials.create("PRIVATE_KEY_TESTNET_SAJA");
ContractGasProvider gasProvider = new DefaultGasProvider();

GoldToken kontrak = GoldToken.load(
    "0xAlamatKontrakYangSudahDiDeploy",
    web3j,
    kredensial,
    gasProvider
);

Memanggil read dan write

// READ — lihat Fase 3 sebelumnya: instan, tanpa gas
BigInteger saldo = kontrak.balanceOf("0xAlamatPengguna").send();

// WRITE — butuh gas, menunggu konfirmasi block
TransactionReceipt receipt = kontrak
    .mintGold("0xAlamatPengguna", BigInteger.valueOf(100), "bukti-001")
    .send();

if (!receipt.isStatusOK()) {
    throw new RuntimeException("Transaksi revert: " + receipt.getTransactionHash());
}

Kenapa keduanya sama-sama RemoteFunctionCall<T>.send(). web3j sengaja menyeragamkan API-nya — perbedaan read/write ditentukan oleh mutability fungsi di ABI (dibaca otomatis oleh generator), bukan oleh method Java yang berbeda. Ini nyaman untuk konsistensi kode, tapi bisa menyembunyikan fakta penting: satu baris .send() mungkin instan, baris lain mungkin memblokir puluhan detik. Baca definisi fungsinya di Solidity, bukan cuma nama methodnya di Java, untuk tahu mana yang mana.

Menangani exception

try {
    TransactionReceipt receipt = kontrak.mintGold(alamat, jumlah, bukti).send();
} catch (org.web3j.protocol.exceptions.TransactionException e) {
    // Transaksi TERKIRIM tapi revert di EVM — gas tetap hangus
    log.error("Revert: {}", e.getMessage());
} catch (java.io.IOException e) {
    // Gagal terhubung ke node — belum tentu transaksi terkirim sama sekali
    log.error("Koneksi RPC gagal: {}", e.getMessage());
}

Dua jenis kegagalan yang butuh penanganan berbeda. TransactionException berarti transaksimu benar-benar diproses jaringan dan revert — kamu tahu pasti hasilnya, gas sudah terpakai. IOException lebih berbahaya: kamu tidak tahu apakah transaksi sempat terkirim ke mempool sebelum koneksi putus. Backend produksi harus punya cara memeriksa ulang status transaksi lewat hash-nya sebelum memutuskan mengirim ulang — mengirim ulang transaksi yang sebenarnya sudah berhasil berarti membayar gas dua kali untuk aksi yang sama.

Latihan: buat proyek Maven kosong, tambahkan dependency web3j-core, generate wrapper Java dari ABI kontrak GoldToken milikmu (Fase 2), lalu tulis satu method Java yang memanggil balanceOf() dan mencetak hasilnya. Tidak perlu private key sama sekali untuk latihan ini — buktikan sendiri bahwa read tidak membutuhkannya.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.