Introducción: ¿Por qué data class no quiere estar vacío?
\n\n¿Alguna vez has intentado crear un data class en Kotlin para Android y te has sorprendido al descubrir que el compilador se niega a aceptar un constructor vacío? Si es así, no estás solo. Esta pregunta ha acumulado miles de visitas en Stack Overflow, lo que significa que cientos de desarrolladores (desde principiantes hasta experimentados) han tropezado con la misma piedra.
¿Por qué sucede esto? El problema es que un data class en Kotlin no es solo una clase para almacenar datos. Genera automáticamente las funciones equals(), hashCode(), toString(), copy() y componentN(). Y para toda esta magia, necesita un constructor primario con al menos un parámetro. Sin él, no hay manera.
En este artículo, analizaremos los 5 errores principales que cometen los desarrolladores al intentar crear un constructor vacío para un data class en Kotlin Android y mostraremos cómo evitarlos. ¡Allá vamos!
Error n.º 1: Declaración directa de un constructor vacío
\n\nEl error más común es intentar escribir algo como:
\n\n// ❌ ¡Así no!\ndata class User {\n constructor() : this() // Error de compilación\n}\n\n\nKotlin exige estrictamente que el constructor primario se declare en el encabezado de la clase. Si intentas crear un constructor secundario sin parámetros que se llame a sí mismo, obtendrás una recursión infinita y un error de compilación.
\n\nSolución: Valores por defecto
\n\nLa forma más sencilla y elegante es asignar valores por defecto a todos los parámetros del constructor primario:
\n\n// ✅ Correcto: valores por defecto\ndata class User(\n val name: String = "",\n val age: Int = 0,\n val email: String = ""\n)\n\n// Ahora se puede crear un objeto sin argumentos\nval emptyUser = User()\nprintln(emptyUser) // User(name=, age=0, email=)\n\n\nEste enfoque funciona "de serie" y no requiere ningún plugin o anotación adicional. Obtienes un constructor vacío completo y todos los campos se inicializan con valores por defecto.
\n\nError n.º 2: Ignorar los requisitos de las bibliotecas (Room, Retrofit, Gson)
\n\nMuchas bibliotecas para Android requieren un constructor vacío para crear objetos mediante reflexión. El ejemplo clásico es Room:
\n\n// ❌ Room dará un error\n@Entity\ndata class User(\n @PrimaryKey val id: Int,\n val name: String,\n val age: Int\n)\n\n\nAl intentar usar este data class con Room, obtendrás una excepción: Cannot instantiate User using no-arg constructor. Problemas similares ocurren con Gson y Retrofit al deserializar JSON.
Solución: Valores por defecto + tipos nullable
\n\nPara Room, basta con añadir valores por defecto:
\n\n// ✅ Room contento\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 y Retrofit, a menudo es más sencillo usar tipos nullable:
\n\n// ✅ Para trabajar con JSON\ndata class ApiResponse(\n val status: String? = null,\n val data: List<Item>? = null\n)\n\n\nPero ten cuidado: los tipos nullable pueden provocar NPE si olvidas verificar el valor. Úsalos con conciencia.
\n\nError n.º 3: Olvidar el plugin Kotlin No-Arg
\n\nA veces los valores por defecto no son adecuados. Por ejemplo, si usas Jackson para la serialización y necesitas tipos específicos sin nullable. En este caso, el plugin kotlin-noarg viene al rescate.
Muchos desarrolladores piensan erróneamente que basta con añadir la dependencia en build.gradle. Pero sin la configuración correcta, el plugin no funcionará.
Solución: Configuración correcta de No-Arg
\n\nAñade el plugin en build.gradle.kt