Introduction : pourquoi votre code Kotlin "casse" soudainement Jackson ?
\n\nAvez-vous déjà écrit en Kotlin une data class belle et concise, ajouté quelques champs, lancé la désérialisation JSON via Jackson — et soudainement reçu une longue erreur effrayante ? Cela vous dit quelque chose ? Si oui, vous n'êtes pas seul. L'erreur "No Creators, like default construct, exist) : cannot deserialize from Object value (no delegate- or property-based Creator)" est l'une des requêtes les plus populaires sur Stack Overflow (des milliers de vues !) parmi les développeurs qui passent de Java à Kotlin.
Dans cet article, nous ne nous contenterons pas de traduire le texte de l'erreur. Nous l'analyserons "au microscope" : pourquoi elle se produit, comment la reproduire, et surtout — comment s'en débarrasser une fois pour toutes. Vous obtiendrez non seulement la théorie, mais aussi des solutions prêtes à l'emploi et éprouvées avec du code Kotlin. C'est parti !
\n\nQue signifie exactement cette erreur ? En termes simples
\n\nImaginons que Jackson est un "constructeur" qui doit assembler un objet de votre classe à partir de briques JSON. Pour construire une maison, le constructeur a besoin d'un plan clair (constructeur) ou au moins d'un ensemble de murs prêts (champs).
\n\nL'erreur "No Creators, like default construct, exist" dit littéralement : "Cher Jackson, je ne peux pas créer un objet de cette classe car il n'a pas de constructeur par défaut (sans paramètres), et je ne sais pas comment l'assembler à partir des champs JSON fournis !"
\n\nEn Java, c'est simple : si vous n'avez écrit aucun constructeur, le compilateur crée aimablement un constructeur vide par défaut. Jackson le voit et l'utilise joyeusement. En Kotlin, si vous définissez une data class avec des paramètres dans le constructeur, le constructeur sans paramètres n'est pas créé automatiquement. Et Jackson, par défaut, le cherche précisément.
Reproduisons le problème : un code qui échouera avec une erreur
\n\nÉcrivons un exemple simple qui provoquera à coup sûr cette erreur. Imaginons que nous avons une classe utilisateur :
\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\n\n// ATTENTION : Ce code provoquera une erreur !\ndata class User(val name: String, val age: Int)\n\nfun main() {\n val mapper: ObjectMapper = jacksonObjectMapper()\n val json = """{"name": "Alexeï", "age": 30}"""\n\n // Tentative de désérialisation du JSON en objet User\n val user: User = mapper.readValue(json)\n println(user)\n}\n\n\nExécutez ce code, et vous obtiendrez la fameuse exception :
\n\ncom.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": "Alexeï", "age": 30}"; line: 1, column: 2]\n\n\nLa voilà, notre "star" de Stack Overflow ! Pourquoi cela s'est-il produit ? Parce que data class User(val name: String, val age: Int) n'a pas de constructeur sans paramètres. Tous ses champs sont déclarés dans le constructeur principal, et ils sont obligatoires (val). Jackson ne peut pas créer un User sans savoir quelles valeurs passer à name et age, et sans avoir d'indications sous forme de setters.
3 méthodes pour corriger l'erreur (de la plus simple à la plus correcte)
\n\nBonne nouvelle : il existe plusieurs solutions. Le choix dépend de la mesure dans laquelle vous souhaitez contrôler le processus et du code que vous considérez comme "propre".
\n\nMéthode 1 : La plus simple (mais pas pour les puristes Kotlin)
\n\nAjouter manuellement un constructeur sans paramètres. En Kotlin, cela se fait en spécifiant des valeurs par défaut pour tous les champs.
\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\n\n// Ou