Property di Kotlin bukan sekadar field — property adalah pasangan getter/setter dengan backing field opsional. Reflection pada property, oleh karena itu, lebih kaya dibanding reflection pada field Java. Pada chapter ini kita akan membahas dua tipe utama (KProperty untuk val, KMutableProperty untuk var), cara mengakses getter dan setter, serta properti khusus seperti isLateinit dan isConst. Pemahaman ini menjadi dasar untuk membangun mapper, serializer, atau validator berbasis reflection.
KProperty vs KMutableProperty #
| Tipe | Cocok untuk | Properti penting |
|---|---|---|
KProperty<T> | val (read-only) | getter, isLateinit, isConst, returnType |
KMutableProperty<T> | var (read-write) | getter, setter, isLateinit |
KProperty1<T, V> | Member property dengan receiver | get(receiver), isLateinit, isConst |
KMutableProperty1<T, V> | Member mutable property | get(receiver), set(receiver, value) |
Hierarki: KMutableProperty extends KProperty. Cast aman dilakukan dengan is/as.
Mendapatkan Reference Property #
Cara mendapatkan reference property:
val prop1: KProperty<String> = Buku::judul // class::property (unbound)
val prop2: () -> String = buku::judul // instance::property (bound)
val prop3 = kelas.memberProperties.first() // via KClassContoh Kode #
Kode berikut mendemonstrasikan property reflection dengan berbagai tipe:
// File: property_reflection.kt
// Mendemonstrasikan property reflection: KProperty, KMutableProperty,
// ::prop syntax, getter.call, isLateinit, isConst.
package com.example.properti
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.memberProperties
class Konfigurasi {
val versi: String = "1.0.0"
var jumlahRetry: Int = 3
lateinit var token: String
}
object Tetapan {
const val NAMA_APP: String = "Aplikasi Demo"
val versi: String = "1.0.0"
}
fun main() {
val kelas = Konfigurasi::class
val instance = Konfigurasi()
instance.token = "ABC123"
println("Properti pada ${kelas.simpleName}:")
for (prop in kelas.memberProperties) {
val nama = prop.name
val tipe = prop.returnType
val isVar = prop is KMutableProperty1<*, *>
val isLate = (prop as? KProperty1<Konfigurasi, *>)?.isLateinit ?: false
val nilai = prop.getter.call(instance)
println(" - $nama: $tipe, var=$isVar, lateinit=$isLate, nilai=$nilai")
}
// Inspeksi const pada object Tetapan.
println("\nProperti object Tetapan:")
for (prop in Tetapan::class.declaredMemberProperties) {
val isConst = prop.isConst
// Untuk const val pada object, getter tidak memerlukan receiver.
val nilai = if (prop.isConst) {
prop.getter.call()
} else {
prop.getter.call(Tetapan)
}
println(" - ${prop.name}: const=$isConst, nilai=$nilai")
}
// Akses langsung via ::prop reference.
val versiProp: KProperty1<Konfigurasi, String> = Konfigurasi::versi
println("\nversiProp.getter.call(instance) = ${versiProp.getter.call(instance)}")
// Cast aman ke KMutableProperty1 untuk akses setter.
val retryPropAny = kelas.memberProperties.first { it.name == "jumlahRetry" }
val retryProp = retryPropAny as KMutableProperty1<Konfigurasi, Int>
retryProp.setter.call(instance, 5)
println("Setelah setter.call(instance, 5): jumlahRetry = ${instance.jumlahRetry}")
}Output yang Dihasilkan:
Properti pada Konfigurasi:
- jumlahRetry: kotlin.Int, var=true, lateinit=false, nilai=3
- token: kotlin.String, var=true, lateinit=true, nilai=ABC123
- versi: kotlin.String, var=false, lateinit=false, nilai=1.0.0
Properti object Tetapan:
- NAMA_APP: const=true, nilai=Aplikasi Demo
- versi: const=false, nilai=1.0.0
versiProp.getter.call(instance) = 1.0.0
Setelah setter.call(instance, 5): jumlahRetry = 5Mari kita bedah baris-baris kunci di atas:
- Baris 14 (
class Konfigurasi): class dengan tiga jenis property —valbiasa,varbiasa, danlateinit var. Ketiganya akan diinspeksi reflection dengan hasil berbeda padaisLateinitdanisVar. - Baris 20 (
object Tetapan): object denganconst val NAMA_APPdanval versi.consthanya boleh dideklarasikan pada top-level atau object. Reflection akan menunjukkanisConst = truepadaNAMA_APP. - Baris 30 (
prop is KMutableProperty1<*, *>): cek apakah property bersifat mutable. HasilnyatrueuntukjumlahRetrydantoken,falseuntukversi. - Baris 31 (
prop as? KProperty1<Konfigurasi, *>)?.isLateinit): cast aman untuk mengaksesisLateinit. Hasilnyatruehanya untuktoken. - Baris 32 (
prop.getter.call(instance)): memanggil getter dengan instance sebagai receiver. Untuk propertytokenyanglateinit, getter mengembalikan nilai yang sudah di-assign. - Baris 38 (
Tetapan::class.declaredMemberProperties):declaredMemberPropertieshanya mengembalikan property yang dideklarasikan di class ini, tidak termasuk warisan dariAny. Berguna untuk menghindari property bawaan sepertitoString. - Baris 42-46 (if prop.isConst): untuk
const valpada object, getter tidak menerima receiver (argumen). Pemanggilangetter.call()tanpa argumen mengembalikan nilai konstanta. Bila kita memanggilgetter.call(Tetapan)pada const val, akan muncul galat “Callable expects 0 arguments”. - Baris 55 (
KProperty1<Konfigurasi, String>): tipe property member dengan receiverKonfigurasidan tipe kembalianString. Penggunaan tipe parameter eksplisit membuat aksesgetter.call(instance)type-safe. - Baris 59 (
as KMutableProperty1<Konfigurasi, Int>): cast ke mutable property untuk akses setter. Tanpa cast, hanyagetteryang tersedia di tipeKProperty1. - Baris 60 (
retryProp.setter.call(instance, 5)): memanggil setter dengan dua argumen — receiver dan nilai baru. Setelah pemanggilan,instance.jumlahRetrymenjadi5.
Lateinit dan Const #
Properti isLateinit bernilai true hanya untuk lateinit var. Properti isConst bernilai true hanya untuk const val pada top-level atau object. Kedua flag ini tidak tersedia pada field Java biasa — fitur Kotlin spesifik.
Bound vs Unbound Reference #
Reference Buku::judul disebut unbound — pemanggilan getter.call(buku) wajib menyertakan receiver. Reference buku::judul disebut bound — receiver sudah terikat, pemanggilan getter.call() tanpa argumen sudah cukup.
Referensi Lanjutan #
- Reflection — bagian property reflection pada panduan reflection resmi
- KProperty API reference
— API reference
KPropertyuntuk introspeksi property
Selanjutnya #
Selain property, kita juga dapat mereferensikan function dan constructor sebagai nilai. Chapter Callable References akan membahas tiga bentuk callable reference: top-level, class::member, dan instance::member.