Introdução: Por que o data class não quer ser vazio?
\n\nVocê já tentou criar um data class em Kotlin para Android e descobriu, surpreso, que o compilador se recusa a aceitar um construtor vazio? Se sim, você não está sozinho. Esta questão acumulou milhares de visualizações no Stack Overflow, o que significa que centenas de desenvolvedores (de iniciantes a experientes) tropeçaram no mesmo obstáculo.
Por que isso acontece? Acontece que o data class em Kotlin não é apenas uma classe para armazenar dados. Ele gera automaticamente as funções equals(), hashCode(), toString(), copy() e componentN(). E para toda essa mágica, ele precisa de um construtor primário com pelo menos um parâmetro. Sem ele, não tem jeito.
Neste artigo, vamos analisar os 5 principais erros que os desenvolvedores cometem ao tentar criar um construtor vazio para data class em Kotlin Android e mostrar como evitá-los. Vamos lá!
Erro nº1: Declaração direta de um construtor vazio
\n\nO erro mais comum é tentar escrever algo como:
\n\n// ❌ Não pode!\ndata class User {\n constructor() : this() // Erro de compilação\n}\n\n\nKotlin exige rigorosamente que o construtor primário seja declarado no cabeçalho da classe. Se você tentar criar um construtor secundário sem parâmetros que chama a si mesmo, obterá uma recursão infinita e um erro de compilação.
\n\nSolução: Valores padrão
\n\nA maneira mais simples e elegante é definir valores padrão para todos os parâmetros do construtor primário:
\n\n// ✅ Correto: valores padrão\ndata class User(\n val name: String = "",\n val age: Int = 0,\n val email: String = ""\n)\n\n// Agora é possível criar um objeto sem argumentos\nval emptyUser = User()\nprintln(emptyUser) // User(name=, age=0, email=)\n\n\nEsta abordagem funciona "de fábrica" e não requer plugins ou anotações adicionais. Você obtém um construtor vazio completo, e todos os campos são inicializados com valores padrão.
\n\nErro nº2: Ignorar os requisitos das bibliotecas (Room, Retrofit, Gson)
\n\nMuitas bibliotecas para Android exigem um construtor vazio para criar objetos via reflexão. O exemplo clássico é o Room:
\n\n// ❌ Room lançará um erro\n@Entity\ndata class User(\n @PrimaryKey val id: Int,\n val name: String,\n val age: Int\n)\n\n\nAo tentar usar esse data class com Room, você receberá uma exceção: Cannot instantiate User using no-arg constructor. Problemas semelhantes ocorrem com Gson e Retrofit ao desserializar JSON.
Solução: Valores padrão + tipos anuláveis
\n\nPara Room, basta adicionar valores padrão:
\n\n// ✅ Room feliz\n@Entity\ndata class User(\n @PrimaryKey val id: Int = 0,\n val name: String = "",\n val age: Int = 0\n)\n\n\nPara Gson e Retrofit, geralmente é mais simples usar tipos anuláveis:
\n\n// ✅ Para trabalhar com JSON\ndata class ApiResponse(\n val status: String? = null,\n val data: List<Item>? = null\n)\n\n\nMas cuidado: tipos anuláveis podem levar a NPE se você esquecer de verificar o valor. Use-os com consciência.
\n\nErro nº3: Plugin Kotlin No-Arg esquecido
\n\nÀs vezes, os valores padrão não são adequados. Por exemplo, se você estiver usando Jackson para serialização e precisar de tipos específicos sem anuláveis. Nesse caso, o plugin kotlin-noarg vem em socorro.
Muitos desenvolvedores pensam erroneamente que basta adicionar a dependência no build.gradle. Mas sem a configuração correta, o plugin não funcionará.
Solução: Configuração correta do No-Arg
\n\nAdicione o plugin no build.gradle.kts: