0Pricing
Kotlin Academy · Lección

Validación y mapeo basados en reflexión

Construya un validador sencillo o un mapeador de objetos mediante reflexión basada en anotaciones.

Validación y mapeo basados en reflexión es una lección gratuita de Kotlin Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Kotlin Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Kotlin Academy incluye 4 lecciones en total.

Qué resuelve este patrón

La validación basada en reflexión lee las anotaciones de las propiedades de una clase en tiempo de ejecución y aplica automáticamente las reglas de validación, sin comprobaciones manuales para cada campo. La misma técnica permite crear mapeadores ORM que convierten objetos en filas de base de datos y viceversa.

La anotación Validate

Defina una anotación con retención en tiempo de ejecución dirigida a propiedades:

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

Anotación de una clase de datos

Aplique @Validate a las propiedades de una clase de datos. El validador las examinará en tiempo de ejecución:

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
)

La función de validación

Use KClass.declaredMemberProperties para iterar sobre las propiedades, buscar anotaciones y recopilar errores:

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
}

Ejecución del validador

Llame a validate() con cualquier objeto anotado. La función devuelve una lista de mensajes de error; una lista vacía indica que el objeto es válido:

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

Asignación de objeto a Map con @Column

Otro patrón de reflexión asigna un objeto a un Map mediante una anotación @Column que proporciona los nombres de las columnas:

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

Uso del asignador

Anote la clase de datos y llame a toMap() para obtener un mapa cuyas claves son nombres de columna, listo para una sentencia 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}

Almacenamiento en caché de los resultados de reflexión

Los análisis mediante reflexión son costosos. Almacene en caché la asociación entre propiedades y anotaciones al iniciar la aplicación, usando un ConcurrentHashMap cuyas claves sean 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 }
        }
}

Combinación de validación y asignación

Puede apilar anotaciones en una sola propiedad y procesar cada una de forma independiente. Primero valide y después asigne, o haga ambas cosas en una sola pasada recopilando cada tipo de anotación:

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

Limitaciones

La validación basada en reflexión es potente, pero tiene algunos inconvenientes: añade sobrecarga en tiempo de ejecución, depende de la retención de las anotaciones y no puede detectar errores en tiempo de compilación. Para una validación crítica para el rendimiento o segura en tiempo de compilación, considere usar código generado con KSP.

Cuándo usar este patrón

La validación basada en reflexión resulta especialmente útil en código de frameworks que debe gestionar clases arbitrarias definidas por el usuario: ORM, serializadores, validadores de formularios y enlazadores de configuración. El código de la aplicación que controla sus propios tipos debería preferir una validación explícita por motivos de rendimiento y claridad.

Comprobación rápida

¿Qué política de retención de anotaciones se necesita para que una anotación de validación se pueda leer en tiempo de ejecución?

Resumen: validación y asignación basadas en reflexión

Conclusiones clave:

  • Declare anotaciones con retención en tiempo de ejecución dirigidas a propiedades
  • Use declaredMemberProperties + findAnnotation para controlar la validación o la asignación
  • Almacene los resultados en caché por KClass para evitar la sobrecarga repetida de la reflexión
  • Apile varias anotaciones en una propiedad para combinar comportamientos
  • Considere KSP como alternativa en tiempo de compilación para rutas críticas para el rendimiento

Preguntas frecuentes

¿La lección «Validación y mapeo basados en reflexión» es gratis?

Sí — el texto completo de «Validación y mapeo basados en reflexión» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Kotlin Academy, actualiza a CoddyKit PRO. El curso de Kotlin Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Validación y mapeo basados en reflexión»?

Construya un validador sencillo o un mapeador de objetos mediante reflexión basada en anotaciones. Practicas Kotlin Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Kotlin Academy?

No se requiere experiencia previa. Kotlin Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Validación y mapeo basados en reflexión»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Kotlin Academy?

Sí. Cada lección de Kotlin Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Reflexión de Kotlin: KClass, KFunction y KProperty
  2. Crear y aplicar anotaciones personalizadas
  3. Leer anotaciones en tiempo de ejecución
  4. Validación y mapeo basados en reflexión
← Volver a Kotlin Academy