Kotlin Academy · leksjon

Refleksjonsbasert validering og mapping

Bygg en enkel validator eller object mapper med annotasjonsdrevet refleksjon.

Leksjon 4 av 413 trinn

Refleksjonsbasert validering og mapping er en gratis leksjon i Kotlin Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Kotlin Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Kotlin Academy inneholder totalt 4 leksjoner.

Hva dette mønsteret løser

Validering basert på refleksjon leser annotasjoner fra egenskapene til en klasse under kjøring og bruker valideringsregler automatisk – uten manuelle kontroller for hvert felt. Den samme teknikken brukes av ORM-mappere som konverterer mellom objekter og rader i databasen.

Annotasjonen Validate

Definer en annotasjon som beholdes ved kjøring, og som retter seg mot egenskaper:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class Validate(
    val minLength: Int = 0,
    val maxLength: Int = Int.MAX_VALUE,
    val pattern: String = ""
)

Annotering av en dataklasse

Bruk @Validate på egenskapene i dataklassen. Validatoren skanner disse under kjøring:

data class UserForm(
    @Validate(minLength = 2, maxLength = 50) val name: String,
    @Validate(pattern = "^[\\w.]+@[\\w]+\\.[a-z]{2,}$") val email: String,
    @Validate(minLength = 8) val password: String
)

Validatorfunksjonen

Bruk KClass.declaredMemberProperties til å iterere over egenskaper, finne annotasjoner og samle inn feil:

fun validate(obj: Any): List<String> {
    val errors = mutableListOf<String>()
    for (prop in obj::class.declaredMemberProperties) {
        val ann = prop.findAnnotation<Validate>() ?: continue
        val value = (prop as KProperty1<Any, *>).get(obj)?.toString() ?: ""
        if (value.length < ann.minLength) errors += "${prop.name}: too short"
        if (value.length > ann.maxLength) errors += "${prop.name}: too long"
        if (ann.pattern.isNotEmpty() && !value.matches(Regex(ann.pattern)))
            errors += "${prop.name}: invalid format"
    }
    return errors
}

Kjøre validatoren

Kall validate() med et vilkårlig annotert objekt. Funksjonen returnerer en liste med feilmeldinger. En tom liste betyr at objektet er gyldig:

val form = UserForm("A", "not-an-email", "short")
val errors = validate(form)
errors.forEach(::println)
// name: too short
// email: invalid format
// password: too short

Objekt-til-Map-tilordning med @Column

Et annet refleksjonsmønster tilordner et objekt til en Map ved hjelp av en @Column-annotasjon som oppgir kolonnenavn:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class Column(val name: String)

fun toMap(obj: Any): Map<String, Any?> =
    obj::class.declaredMemberProperties
        .mapNotNull { prop ->
            val col = prop.findAnnotation<Column>() ?: return@mapNotNull null
            col.name to (prop as KProperty1<Any, *>).get(obj)
        }.toMap()

Bruke tilordneren

Annoter dataklassen og kall toMap() for å hente et kolonnenøkkelbasert map som er klart for en INSERT-setning:

data class User(
    @Column("user_name") val name: String,
    @Column("user_email") val email: String
)

val user = User("Alice", "alice@example.com")
println(toMap(user))
// {user_name=Alice, user_email=alice@example.com}

Bufring av refleksjonsresultater

Refleksjonsskanninger er kostbare. Bufre tilordningen mellom egenskaper og annotasjoner ved oppstart ved hjelp av en ConcurrentHashMap med nøkkel av typen KClass:

val cache = ConcurrentHashMap<KClass<*>, List<Pair<KProperty1<Any,*>, Column>>>()

fun columnsOf(klass: KClass<*>) = cache.getOrPut(klass) {
    klass.declaredMemberProperties
        .mapNotNull { p ->
            p.findAnnotation<Column>()?.let { (p as KProperty1<Any,*>) to it }
        }
}

Kombinere validering og tilordning

De kan legge flere annotasjoner på én egenskap og behandle hver av dem uavhengig. Valider først og tilordne deretter – eller gjør begge deler i én gjennomgang ved å samle hver annotasjonstype:

data class Product(
    @Validate(minLength = 1) @Column("product_name") val name: String,
    @Column("price") val price: Double
)

Begrensninger

Refleksjonsbasert validering er kraftig, men har noen avveininger: Den gir ekstra belastning under kjøring, er avhengig av at annotasjonene beholdes, og kan ikke oppdage feil under kompilering. For validering som er kritisk for ytelsen eller skal være sikker under kompilering, bør De i stedet vurdere KSP-generert kode.

Når dette mønsteret bør brukes

Refleksjonsbasert validering er spesielt nyttig i rammeverkskode som må håndtere vilkårlige brukerdefinerte klasser: ORM-er, serializere, skjemavalidatorer og konfigurasjonsbindere. Programkode som selv eier typene sine, bør foretrekke eksplisitt validering for bedre ytelse og tydelighet.

Kort kontroll

Hvilken retensjonspolicy for annotasjoner kreves for at en valideringsannotasjon skal kunne leses under kjøring?

Oppsummering: Refleksjonsbasert validering og tilordning

Viktigste punkter:

  • Deklarer annotasjoner som beholdes ved kjøring, og som retter seg mot egenskaper
  • Bruk declaredMemberProperties + findAnnotation til å styre validering eller tilordning
  • Bufre resultater per KClass for å unngå gjentatt refleksjonsbelastning
  • Legg flere annotasjoner på en egenskap for kombinert atferd
  • Vurder KSP som et alternativ ved kompilering i ytelseskritiske deler av koden
Gratis å komme i gang

Lær deg Kotlin med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
51
Leksjoner
203

Ofte stilte spørsmål

Er leksjonen «Refleksjonsbasert validering og mapping» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Kotlin Academy, inkludert «Refleksjonsbasert validering og mapping», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Kotlin Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Refleksjonsbasert validering og mapping»?

Bygg en enkel validator eller object mapper med annotasjonsdrevet refleksjon. Du øver på Kotlin Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Kotlin Academy?

Ingen tidligere erfaring er nødvendig. Kotlin Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «Refleksjonsbasert validering og mapping»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Kotlin Academy-leksjonen?

Ja. Alle Kotlin Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Kotlin-refleksjon: KClass, KFunction, KProperty
  2. Opprette og målrette egendefinerte annotasjoner
  3. Lese annotasjoner under kjøring
  4. Refleksjonsbasert validering og mapping
← Tilbake til Kotlin Academy