Kotlin Academy · Aula

Validação e mapeamento baseados em reflexão

Crie um validador simples ou um mapeador de objetos usando reflexão orientada por anotações.

Aula 4 de 413 etapas

Validação e mapeamento baseados em reflexão é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Kotlin Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Kotlin Academy inclui 4 aulas no total.

O que este padrão resolve

A validação baseada em reflexão lê anotações das propriedades de uma classe em tempo de execução e aplica regras de validação automaticamente — sem verificações manuais para cada campo. A mesma técnica é usada por mapeadores ORM que convertem objetos em linhas do banco de dados e vice-versa.

A anotação Validate

Defina uma anotação mantida em tempo de execução e direcionada a propriedades:

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

Anotação de uma classe de dados

Aplique @Validate às propriedades da classe de dados. O validador as examinará em tempo de execução:

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
)

A função validadora

Use KClass.declaredMemberProperties para percorrer as propriedades, localizar as anotações e coletar os erros:

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
}

Executando o validador

Chame validate() com qualquer objeto anotado. A função retorna uma lista de mensagens de erro; uma lista vazia significa que o objeto é 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

Mapeamento de objeto para mapa com @Column

Outro padrão de reflexão mapeia um objeto para um Map usando uma anotação @Column para fornecer os nomes das colunas:

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

Usando o mapeador

Anote a classe de dados e chame toMap() para obter um mapa indexado por colunas, pronto para uma instrução 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}

Armazenando em cache os resultados da reflexão

As varreduras de reflexão são dispendiosas. Armazene em cache, na inicialização, o mapeamento de propriedades para anotações usando um ConcurrentHashMap indexado por 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 }
        }
}

Combinando validação e mapeamento

Você pode empilhar anotações em uma única propriedade e processar cada uma de forma independente. Primeiro valide e depois mapeie — ou faça ambas as operações em uma única passagem, coletando cada tipo de anotação:

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

Limitações

A validação baseada em reflexão é poderosa, mas envolve algumas concessões: acrescenta sobrecarga em tempo de execução, depende da retenção das anotações e não consegue detectar erros em tempo de compilação. Para uma validação crítica para o desempenho ou segura em tempo de compilação, considere código gerado pelo KSP.

Quando usar este padrão

A validação baseada em reflexão é especialmente útil em código de estruturas que precisa lidar com classes arbitrárias definidas pelo usuário: mapeadores objeto-relacional, serializadores, validadores de formulários e vinculadores de configuração. O código da aplicação que controla seus próprios tipos deve preferir a validação explícita, por sua velocidade e clareza.

Verificação rápida

Qual política de retenção de anotações é necessária para que uma anotação de validação possa ser lida em tempo de execução?

Recapitulação: validação e mapeamento baseados em reflexão

Principais conclusões:

  • Declare anotações mantidas em tempo de execução e direcionadas a propriedades
  • Use declaredMemberProperties + findAnnotation para conduzir a validação ou o mapeamento
  • Armazene os resultados em cache por KClass para evitar a sobrecarga de reflexão repetida
  • Empilhe várias anotações em uma propriedade para combinar comportamentos
  • Considere o KSP para alternativas em tempo de compilação em trechos críticos para o desempenho
Grátis para começar

Aprenda Kotlin com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
51
Aulas
203

Perguntas Frequentes

A aula “Validação e mapeamento baseados em reflexão” é grátis?

Sim — o texto completo de “Validação e mapeamento baseados em reflexão” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Kotlin Academy, atualize para CoddyKit PRO. O curso de Kotlin Academy inclui 4 aulas no total.

O que vou aprender em “Validação e mapeamento baseados em reflexão”?

Crie um validador simples ou um mapeador de objetos usando reflexão orientada por anotações. Você pratica Kotlin Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Kotlin Academy?

Nenhuma experiência prévia é necessária. Kotlin Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Validação e mapeamento baseados em reflexão”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Kotlin Academy?

Sim. Cada aula de Kotlin Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Reflexão no Kotlin: KClass, KFunction, KProperty
  2. Criando e direcionando anotações personalizadas
  3. Lendo anotações em tempo de execução
  4. Validação e mapeamento baseados em reflexão
← Voltar para Kotlin Academy