0Pricing
Kotlin Academy · Lekcja

Walidacja i mapowanie oparte na refleksji

Zbuduj prosty walidator lub mapper obiektów wykorzystujący refleksję sterowaną adnotacjami.

Walidacja i mapowanie oparte na refleksji to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co rozwiązuje ten schemat

Walidacja oparta na refleksji odczytuje w czasie działania adnotacje z właściwości klasy i automatycznie stosuje reguły walidacji — bez ręcznych kontroli każdego pola. Ta sama technika zasila mappery ORM, które konwertują obiekty na wiersze bazy danych i odwrotnie.

Adnotacja Validate

Należy zdefiniować adnotację zachowywaną w czasie działania, przeznaczoną do stosowania na właściwościach:

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

Oznaczanie klasy danych adnotacją

Należy zastosować @Validate do właściwości klasy danych. Walidator odczyta je w czasie działania:

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
)

Funkcja walidatora

Należy użyć KClass.declaredMemberProperties, aby przeiterować po właściwościach, znaleźć adnotacje i zebrać błędy:

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
}

Uruchamianie walidatora

Należy wywołać validate() z dowolnym obiektem zawierającym adnotacje. Funkcja zwraca listę komunikatów o błędach; pusta lista oznacza poprawność:

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

Mapowanie obiektu na mapę za pomocą @Column

Inny wzorzec refleksji mapuje obiekt na Map przy użyciu adnotacji @Column, która dostarcza nazwy kolumn:

@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()

Korzystanie z mappera

Należy oznaczyć klasę danych adnotacją i wywołać toMap(), aby uzyskać mapę z kluczami odpowiadającymi kolumnom, gotową do użycia w instrukcji INSERT:

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}

Buforowanie wyników refleksji

Skanowanie za pomocą refleksji jest kosztowne. Należy buforować mapowanie właściwości na adnotacje podczas uruchamiania aplikacji, używając ConcurrentHashMap z kluczami typu 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 }
        }
}

Łączenie walidacji i mapowania

Można nałożyć wiele adnotacji na jedną właściwość i przetwarzać każdą niezależnie. Najpierw należy przeprowadzić walidację, a następnie mapowanie — albo wykonać obie czynności w jednym przebiegu, zbierając każdy typ adnotacji:

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

Ograniczenia

Walidacja oparta na refleksji jest zaawansowana, ale wiąże się z kompromisami: zwiększa narzut w czasie działania, zależy od retencji adnotacji i nie może wykrywać błędów w czasie kompilacji. W przypadku walidacji wymagającej wysokiej wydajności lub bezpieczeństwa na etapie kompilacji warto rozważyć kod generowany przez KSP.

Kiedy stosować ten wzorzec

Walidacja oparta na refleksji sprawdza się szczególnie dobrze w kodzie frameworków, który musi obsługiwać dowolne klasy definiowane przez użytkowników: ORM-y, serializatory, walidatory formularzy i bindery konfiguracji. Kod aplikacji, który kontroluje własne typy, powinien preferować jawną walidację ze względu na szybkość i czytelność.

Szybkie sprawdzenie

Jaka polityka retencji adnotacji jest wymagana, aby adnotacja walidacji była dostępna w czasie działania?

Podsumowanie: walidacja i mapowanie oparte na refleksji

Najważniejsze informacje:

  • Należy deklarować adnotacje zachowywane w czasie działania i przeznaczone dla właściwości
  • Należy używać declaredMemberProperties wraz z findAnnotation do sterowania walidacją lub mapowaniem
  • Należy buforować wyniki dla każdego KClass, aby uniknąć powtarzalnego narzutu refleksji
  • Można nakładać wiele adnotacji na właściwość, aby łączyć ich działanie
  • W ścieżkach krytycznych pod względem wydajności warto rozważyć KSP jako alternatywę działającą w czasie kompilacji

Często zadawane pytania

Czy lekcja „Walidacja i mapowanie oparte na refleksji” jest bezpłatna?

Tak — pełny tekst „Walidacja i mapowanie oparte na refleksji” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Walidacja i mapowanie oparte na refleksji”?

Zbuduj prosty walidator lub mapper obiektów wykorzystujący refleksję sterowaną adnotacjami. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Walidacja i mapowanie oparte na refleksji”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Refleksja w Kotlinie: KClass, KFunction, KProperty
  2. Tworzenie własnych adnotacji i określanie ich celów
  3. Odczytywanie adnotacji w czasie działania
  4. Walidacja i mapowanie oparte na refleksji
← Powrót do Kotlin Academy