Introdução: por que seu código Kotlin de repente "quebra" o Jackson?
Você já escreveu em Kotlin um data class bonito e conciso, adicionou alguns campos, executou a desserialização JSON via Jackson — e de repente recebeu um erro longo e assustador? Familiar? Se sim, você não está sozinho. O erro "No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator" é uma das perguntas mais populares no Stack Overflow (milhares de visualizações!) entre desenvolvedores que estão migrando de Java para Kotlin.
Neste artigo, não vamos apenas traduzir o texto do erro. Vamos analisá-lo "sob o microscópio": por que ele ocorre, como reproduzi-lo e, o mais importante, como se livrar dele de uma vez por todas. Você receberá não apenas teoria, mas também soluções prontas e testadas com código em Kotlin. Vamos lá!
O que esse erro significa? Em palavras simples
Vamos imaginar que o Jackson é um "construtor" que precisa montar um objeto da sua classe a partir dos blocos JSON. Para construir uma casa, o construtor precisa de uma planta clara (construtor) ou pelo menos de um conjunto de paredes prontas (campos).
O erro "No Creators, like default construct, exist" literalmente diz: "Prezado Jackson, não consigo criar um objeto desta classe porque ela não tem um construtor padrão (sem parâmetros) e não sei como montá-lo a partir dos campos JSON fornecidos!"
Em Java, é simples: se você não escreveu nenhum construtor, o compilador cria gentilmente um construtor vazio padrão. O Jackson o vê e o utiliza alegremente. Em Kotlin, no entanto, se você define um data class com parâmetros no construtor, o construtor sem parâmetros não é criado automaticamente. E o Jackson, por padrão, procura exatamente por ele.
Reproduzindo o problema: código que gerará o erro
Vamos escrever um exemplo simples que certamente causará esse erro. Imagine que temos uma classe de usuário:
import com.fasterxml.jackson.databind.ObjectMapperimport com.fasterxml.jackson.module.kotlin.readValueimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
// ATENÇÃO: Este código causará um erro!data class User(val name: String, val age: Int)
fun main() { val mapper: ObjectMapper = jacksonObjectMapper() val json = """{"name": "Alexei", "age": 30}"""
// Tentando desserializar JSON para um objeto User val user: User = mapper.readValue(json) println(user)}Execute este código e você obterá a famosa exceção:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `User` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{"name": "Alexei", "age": 30}"; line: 1, column: 2]Aí está, nossa "estrela" do Stack Overflow! Por que isso aconteceu? Porque data class User(val name: String, val age: Int) não tem um construtor sem parâmetros. Todos os seus campos são declarados no construtor primário e são obrigatórios (val). O Jackson não pode criar um User sem saber quais valores passar para name e age, e sem ter dicas na forma de setters.
3 formas de corrigir o erro (do simples ao correto)
A boa notícia: existem várias soluções. A escolha depende de quanto você deseja controlar o processo e qual código considera "limpo".
Forma 1: A mais simples (mas não para puristas do Kotlin)
Adicionar um construtor sem parâmetros manualmente. Em Kotlin, isso é feito definindo valores padrão para todos os campos.
import com.fasterxml.jackson.databind.ObjectMapperimport com.fasterxml.jackson.module.kotlin.readValueimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
// Sim