Le constructeur sans argument est une exigence (des outils comme Hibernate utilisent la réflexion sur ce constructeur pour instancier des objets).
J'ai eu cette réponse ondulée mais quelqu'un pourrait-il expliquer davantage? Merci
Le constructeur sans argument est une exigence (des outils comme Hibernate utilisent la réflexion sur ce constructeur pour instancier des objets).
J'ai eu cette réponse ondulée mais quelqu'un pourrait-il expliquer davantage? Merci
The no-argument constructor is a requirement
est fausse , et toutes les réponses qui continuent à expliquer pourquoi il en est ainsi sans se demander s'il en est effectivement ainsi (y compris la réponse acceptée, qui a même reçu une prime,) sont fausses . Voir cette réponse: stackoverflow.com/a/29433238/773113Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
comme dans le cas où je viens de rencontrerRéponses:
Hibernate, et le code en général qui crée des objets via la réflexion utilise
Class<T>.newInstance()
pour créer une nouvelle instance de vos classes. Cette méthode nécessite un constructeur public sans argument pour pouvoir instancier l'objet. Pour la plupart des cas d'utilisation, fournir un constructeur sans argument n'est pas un problème.Il existe des hacks basés sur la sérialisation qui peuvent contourner le fait de ne pas avoir de constructeur sans argument, car la sérialisation utilise la magie jvm pour créer des objets sans appeler le constructeur. Mais ce n'est pas disponible sur toutes les VM. Par exemple, XStream peut créer des instances d'objets qui n'ont pas de constructeur public no-arg, mais uniquement en s'exécutant dans un mode dit "amélioré" qui n'est disponible que sur certaines VM. (Voir le lien pour plus de détails.) Les concepteurs d'Hibernate ont sûrement choisi de maintenir la compatibilité avec toutes les machines virtuelles et évite ainsi de telles astuces, et utilise la méthode de réflexion officiellement prise en charge
Class<T>.newInstance()
nécessitant un constructeur sans argument.la source
setAccessible(true)
.ObjectInputStream
fait quelque chose commesun.reflect.ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToGetInstanceOf, Object.class.getConstructor()).newInstance()
pour instancier des objets sans constructeur par défaut (JDK1.6 pour Windows)It can have package visibility and Hibernate should setAccessible(true)
. Celait
signifie- t - il que la classe est instanciée par réflexion? Et qu'est-ce que çaHibernate should setAccessible(true)
veut dire?Hibernate instancie vos objets. Il doit donc être en mesure de les instancier. S'il n'y a pas de constructeur no-arg, Hibernate ne saura pas comment l' instancier, c'est-à-dire quel argument passer.
La documentation de mise en veille prolongée dit:
Toutes les classes persistantes doivent avoir un constructeur par défaut (qui peut être non public) pour qu'Hibernate puisse les instancier en utilisant
Constructor.newInstance()
. Il est recommandé d'avoir un constructeur par défaut avec au moins une visibilité sur les packages pour la génération de proxy d'exécution dans Hibernate.la source
Euh, désolé tout le monde, mais Hibernate n'exige pas que vos classes aient un constructeur sans paramètre. La spécification JPA 2.0 exige, et c'est très boiteux de la part de JPA. D'autres frameworks comme JAXB l'exigent également, ce qui est également très boiteux de la part de ces frameworks.
(En fait, JAXB autorise soi-disant les usines d'entités, mais il insiste pour instancier ces usines par lui-même, en leur demandant d'avoir un - devinez quoi-- constructeur sans paramètre , ce qui dans mon livre est exactement aussi bon que de ne pas autoriser les usines; à quel point est-ce que !)
Mais Hibernate n'exige pas une telle chose.
Hibernate prend en charge un mécanisme d'interception, (voir «Intercepteur» dans la documentation ,) qui vous permet d'instancier vos objets avec les paramètres de constructeur dont ils ont besoin.
Fondamentalement, ce que vous faites est que lorsque vous configurez la mise en veille prolongée, vous lui transmettez un objet implémentant l'
org.hibernate.Interceptor
interface, et la mise en veille prolongée appellera alors lainstantiate()
méthode de cette interface chaque fois qu'elle a besoin d'une nouvelle instance d'un de vos objets, de sorte que votre implémentation de cette méthode peutnew
vos objets comme vous le souhaitez.Je l'ai fait dans un projet et cela fonctionne comme un charme. Dans ce projet, je fais les choses via JPA chaque fois que c'est possible, et je n'utilise les fonctionnalités Hibernate comme l'intercepteur que lorsque je n'ai pas d'autre option.
Hibernate semble être quelque peu incertain à ce sujet, car au démarrage, il émet un message d'information pour chacune de mes classes d'entité, me disant
INFO: HHH000182: No default (no-argument) constructor for class
etclass must be instantiated by Interceptor
, mais plus tard, je les instancie par intercepteur, et il en est satisfait.Pour répondre à la partie «pourquoi» de la question pour les outils autres qu'Hibernate , la réponse est «sans aucune raison valable», et cela est prouvé par l'existence de l'intercepteur d'hibernation. Il existe de nombreux outils qui auraient pu prendre en charge un mécanisme similaire pour l'instanciation d'objet client, mais ils ne le font pas, ils créent donc les objets eux-mêmes, ils doivent donc nécessiter des constructeurs sans paramètre. Je suis tenté de croire que cela se produit parce que les créateurs de ces outils se considèrent comme des programmeurs de systèmes ninja qui créent des cadres pleins de magie à utiliser par des programmeurs d'applications ignorants, qui (selon eux) n'auraient jamais dans leurs rêves les plus fous besoin de constructions avancées comme le ... Factory Pattern . (D'accord,penser ainsi. Je ne pense pas vraiment . Je plaisante.)
la source
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
qui s'est produit récemment car iljavax.persistence.*;
est utilisé et uniquementorg.hibernate
lors de la création duSession, SessionFactory, and Configuration
La mise en veille prolongée est un framework ORM qui prend en charge la stratégie d'accès aux champs ou aux propriétés. Cependant, il ne prend pas en charge le mappage basé sur le constructeur - peut-être que vous aimeriez? - à cause de certains problèmes comme
1º Que se passe-t-il si votre classe contient beaucoup de constructeurs
Comme vous pouvez le voir, vous gérez un problème d'incohérence car Hibernate ne peut pas supposer quel constructeur doit être appelé. Par exemple, supposons que vous ayez besoin de récupérer un objet Person stocké
Quel constructeur doit appeler Hibernate pour récupérer un objet Person? Peux tu voir ?
2º Et enfin, en utilisant la réflexion, Hibernate peut instancier une classe via son constructeur sans argument. Alors quand tu appelles
Hibernate instanciera votre objet Person comme suit
Qui selon la documentation de l'API
Morale de l'histoire
est similaire à
Rien d'autre
la source
name
etage
? Sinon, il utilise un autre constructeur plus tard?En fait, vous pouvez instancier des classes qui n'ont pas de constructeur 0-args; vous pouvez obtenir une liste des constructeurs d'une classe, en choisir un et l'invoquer avec de faux paramètres.
Bien que cela soit possible, et je suppose que cela fonctionnerait et ne serait pas problématique, vous devrez convenir que c'est assez étrange.
Construire des objets comme le fait Hibernate (je crois qu'il invoque le constructeur 0-arg, puis il modifie probablement les champs de l'instance directement via Reflection. Peut-être qu'il sait comment appeler des setters) va un peu à l'encontre de la façon dont un objet est censé être construit dans Java - invoquez le constructeur avec les paramètres appropriés pour que le nouvel objet soit l'objet souhaité. Je crois qu'instancier un objet puis le muter est un peu "anti-Java" (ou je dirais, anti pur Java théorique) - et certainement, si vous faites cela via une manipulation directe de champ, cela passe par l'encapsulation et tout ce truc d'encapsulation sophistiqué .
Je pense que la bonne façon de faire cela serait de définir dans le mappage Hibernate comment un objet devrait être instancié à partir des informations de la ligne de base de données en utilisant le constructeur approprié ... mais ce serait plus complexe - ce qui signifie que les deux Hibernate seraient même plus complexe, la cartographie serait plus complexe ... et tout cela pour être plus "pur"; et je ne pense pas que cela aurait un avantage sur l'approche actuelle (autre que se sentir bien de faire les choses "de la bonne manière").
Cela dit, et vu que l'approche Hibernate n'est pas très "propre", l'obligation d'avoir un constructeur 0-arg n'est pas strictement nécessaire, mais je peux comprendre quelque peu l'exigence, même si je pense qu'ils l'ont fait de manière purement "correcte "motifs, lorsqu'ils se sont écartés de la" bonne voie "(quoique pour des raisons raisonnables) bien avant cela.
la source
Hibernate doit créer des instances à la suite de vos requêtes (via la réflexion), Hibernate s'appuie sur le constructeur d'entités no-arg pour cela, vous devez donc fournir un constructeur no-arg. Qu'est-ce qui n'est pas clair?
la source
private
constructeur est-il incorrect? Je voisjava.lang.InstantiationException
même avec unprivate
constructeur pour mon entité JPA. référence .Il est beaucoup plus facile de créer un objet avec un constructeur sans paramètre par réflexion, puis de remplir ses propriétés de données par réflexion, que d'essayer de faire correspondre des données à des paramètres arbitraires d'un constructeur paramétré, avec des changements de noms / conflits de dénomination, une logique non définie à l'intérieur du constructeur, ensembles de paramètres ne correspondant pas aux propriétés d'un objet, et cetera.
De nombreux ORM et sérialiseurs nécessitent des constructeurs sans paramètre, car les constructeurs paramétrés par réflexion sont très fragiles et les constructeurs sans paramètre fournissent à la fois la stabilité de l'application et le contrôle du comportement de l'objet pour le développeur.
la source
Hibernate utilise des proxies pour le chargement différé. Si vous ne définissez pas de constructeur ou ne le rendez pas privé, certaines choses peuvent toujours fonctionner - celles qui ne dépendent pas du mécanisme de proxy. Par exemple, charger l'objet (sans constructeur) directement à l'aide de l'API de requête.
Mais, si vous utilisez la méthode session.load (), vous serez confronté à InstantiationException de la bibliothèque du générateur de proxy en raison de la non-disponibilité du constructeur.
Ce type a signalé une situation similaire:
http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html
la source
Consultez cette section de la spécification du langage Java qui explique la différence entre les classes internes statiques et non statiques: http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3
Une classe interne statique n'est pas différente du point de vue conceptuel d'une classe générale ordinaire déclarée dans un fichier .java.
Étant donné qu'Hibernate doit instancier ProjectPK indépendamment de l'instance Project, ProjectPK doit soit être une classe interne statique, soit être déclaré dans son propre fichier .java.
reference org.hibernate.InstantiationException: aucun constructeur par défaut
la source