Kotlin avec JPA : comment vaincre l'enfer du constructeur par défaut

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Découvrez : « L'enfer du constructeur vide » dans Kotlin + JPA

\n\n

Si vous avez déjà essayé de faire fonctionner ensemble Kotlin et JPA (Java Persistence API), vous avez probablement rencontré une situation où, au lancement de l'application, Hibernate lève une exception du genre :

\n\n
org.hibernate.InstantiationException: No default constructor for entity: com.example.User\n
\n\n

Cela vous dit quelque chose ? Bien sûr. C'est ce problème qui a rassemblé des milliers de vues sur Stack Overflow et a reçu le nom sinistre de « Kotlin with JPA: default constructor hell ».

\n\n

Dans cet article, nous allons calmement, étape par étape, analyser :

\n
    \n
  • Pourquoi cette erreur se produit-elle ?
  • \n
  • Pourquoi Kotlin « ne veut-il pas » générer un constructeur vide ?
  • \n
  • Trois méthodes éprouvées pour résoudre le problème (de la plus simple à la plus professionnelle)
  • \n
  • Quelle méthode choisir pour votre projet
  • \n
\n\n

C'est parti !

\n\n

Pourquoi Hibernate exige-t-il un constructeur sans paramètres ?

\n\n

Commençons par Java. En Java classique, nous avons l'habitude d'écrire :

\n\n
public class User {\n    private Long id;\n    private String name;\n\n    // Constructeur vide obligatoire\n    public User() {}\n\n    // Getters, setters...\n}\n
\n\n

Hibernate (et toute implémentation JPA) utilise la réflexion pour créer des objets. Lorsqu'il lit une ligne de la base de données, il doit créer une instance de la classe User, puis remplir les champs par réflexion. Pour cela, il a besoin d'un constructeur sans paramètres (default constructor).

\n\n

En Java, le compilateur crée automatiquement un constructeur vide si vous n'en avez défini aucun autre. Par conséquent, le problème ne se pose généralement pas.

\n\n

Et quelle est la particularité de Kotlin ?

\n\n

Kotlin est un langage qui met fortement l'accent sur l'immuabilité et la sécurité. Regardez une classe Kotlin typique :

\n\n
data class User(\n    val id: Long = 0,\n    val name: String = ""\n)\n
\n\n

Deux choses clés se produisent ici :

\n
    \n
  • Toutes les propriétés sont déclarées dans le constructeur primaire (primary constructor)
  • \n
  • Les propriétés sont déclarées comme val (immuables) et ont des valeurs par défaut
  • \n
\n\n

Kotlin ne génère pas de constructeur vide séparé si vous avez un constructeur primaire avec des paramètres. Même si tous les paramètres ont des valeurs par défaut, cela n'est pas considéré comme un « vrai » constructeur sans paramètres au niveau du bytecode JVM.

\n\n

Lorsque Hibernate tente d'appeler User.class.newInstance() par réflexion, il ne trouve pas de constructeur vide et échoue avec une erreur.

\n\n

Méthode 1 : La plus simple — ajouter explicitement un constructeur secondaire

\n\n

La voie la plus directe est d'ajouter un deuxième constructeur, vide, manuellement :

\n\n
data class User(\n    val id: Long = 0,\n    val name: String = ""\n) {\n    // Constructeur secondaire sans paramètres\n    constructor() : this()\n}\n
\n\n

Ici, constructor() : this() signifie : « appelle le constructeur primaire avec les valeurs par défaut ».

\n\n

Avantages :

\n
    \n
  • Très simple et clair
  • \n
  • Ne nécessite aucun plugin ni configuration supplémentaire
  • \n
\n\n

Inconvénients :

\n
    \n
  • Il faut écrire ce constructeur pour chaque entité
  • \n
  • Si vous avez 10 à 15 entités, cela devient fastidieux
  • \n
  • Facile à oublier d'ajouter
  • \n
\n\n

Méthode 2 : Utiliser une classe ouverte et rendre toutes les propriétés var

\n\n

De nombreux exemples sur Internet proposent cette solution :

\n\n
open class User {\n    var id: Long = 0\n    var name: String = ""\n}\n
\n\n

Ici, nous rendons la classe open (pour que Hibernate puisse créer un proxy), et les propriétés — var (mutables). Et pas de constructeur primaire — donc Kotlin générera un constructeur vide par défaut.

\n\n

Avantages :

\n
    \n

Blogs

Book Recommendations