Jackson en Kotlin: cómo corregir el error "No Creators, like default construct, exist"

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿por qué tu código en Kotlin de repente "rompe" a Jackson?

\n\n

¿Alguna vez has escrito en Kotlin una hermosa y concisa data class, le has añadido un par de campos, has ejecutado la deserialización JSON con Jackson y de repente te has encontrado con un error largo y aterrador? ¿Te suena? Si es así, no estás solo. El error "No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator" es una de las consultas más populares en Stack Overflow (¡miles de visitas!) entre los desarrolladores que migran de Java a Kotlin.

\n\n

En este artículo no solo traduciremos el texto del error. Lo analizaremos "bajo el microscopio": por qué ocurre, cómo reproducirlo y, lo más importante, cómo deshacerse de él de una vez por todas. Obtendrás no solo teoría, sino también soluciones listas y probadas con código en Kotlin. ¡Allá vamos!

\n\n

¿Qué significa realmente este error? En palabras sencillas

\n\n

Imaginemos que Jackson es como un "constructor" que necesita ensamblar un objeto de tu clase a partir de los ladrillos del JSON. Para construir una casa, el constructor necesita un plano claro (constructor) o al menos un conjunto de paredes prefabricadas (campos).

\n\n

El error "No Creators, like default construct, exist" literalmente dice: "Estimado Jackson, no puedo crear un objeto de esta clase porque no tiene un constructor por defecto (sin parámetros) y no sé cómo ensamblarlo a partir de los campos JSON proporcionados"

\n\n

En Java es simple: si no escribes ningún constructor, el compilador crea amablemente un constructor vacío por defecto. Jackson lo ve y lo usa con alegría. En Kotlin, en cambio, si defines una data class con parámetros en el constructor, el constructor sin parámetros no se crea automáticamente. Y Jackson, por defecto, busca precisamente ese.

\n\n

Reproduciendo el problema: código que fallará con el error

\n\n

Escribamos un ejemplo simple que garantice provocar este error. Imaginemos que tenemos una clase de usuario:

\n\n
import com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\n\n// ATENCIÓN: ¡Este código provocará un error!\ndata class User(val name: String, val age: Int)\n\nfun main() {\n    val mapper: ObjectMapper = jacksonObjectMapper()\n    val json = """{"name": "Alejandro", "age": 30}"""\n\n    // Intentamos deserializar JSON en un objeto User\n    val user: User = mapper.readValue(json)\n    println(user)\n}\n
\n\n

Ejecuta este código y obtendrás la famosa excepción:

\n\n
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: \nCannot construct instance of `User` (no Creators, like default construct, exist): \ncannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (String)"{"name": "Alejandro", "age": 30}"; line: 1, column: 2]\n
\n\n

¡Ahí está, nuestra "estrella" de Stack Overflow! ¿Por qué ocurrió esto? Porque data class User(val name: String, val age: Int) no tiene un constructor sin parámetros. Todos sus campos están declarados en el constructor primario y son obligatorios (val). Jackson no puede crear un User sin saber qué valores pasar a name y age, y sin tener pistas en forma de setters.

\n\n

3 formas de corregir el error (de la más simple a la más correcta)

\n\n

La buena noticia: hay varias soluciones. La elección depende de cuánto quieras controlar el proceso y qué código consideres "limpio".

\n\n

Forma 1: La más simple (pero no para los puristas de Kotlin)

\n\n

Añadir un constructor sin parámetros manualmente. En Kotlin esto se hace especificando valores por defecto para todos los campos.

\n\n
import com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\n\n// Sí                

Blogs

Book Recommendations