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 shortMapowanie 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ć
declaredMemberPropertieswraz zfindAnnotationdo 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
- Refleksja w Kotlinie: KClass, KFunction, KProperty
- Tworzenie własnych adnotacji i określanie ich celów
- Odczytywanie adnotacji w czasie działania
- Walidacja i mapowanie oparte na refleksji