Le constructeur sans argument est une exigence (des outils comme Hibernate utilisent réflexion sur ce constructeur pour instancier les objets).
J'ai obtenu cette réponse à la main mais quelqu'un pourrait-il m'expliquer davantage ? Merci
Le constructeur sans argument est une exigence (des outils comme Hibernate utilisent réflexion sur ce constructeur pour instancier les objets).
J'ai obtenu cette réponse à la main mais quelqu'un pourrait-il m'expliquer davantage ? Merci
Hibernate, et le code en général qui crée des objets via la réflexion utilisent [Class<T>.newInstance()
](http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance()) pour créer une nouvelle instance de vos classes. Cette méthode nécessite un constructeur public no-arg pour pouvoir instancier l'objet. Pour la plupart des cas d'utilisation, fournir un constructeur no-arg n'est pas un problème.
Il existe des astuces basées sur la sérialisation qui peuvent contourner l'absence d'un constructeur sans argument, puisque la sérialisation utilise la magie de JVM pour créer des objets sans invoquer le constructeur. Mais ceci n'est pas disponible sur toutes les VMs. Par exemple, XStream peut créer des instances d'objets qui n'ont pas de constructeur public sans argument, mais seulement 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). (Voir le lien pour plus de détails.) Les concepteurs d'Hibernate ont sûrement choisi de maintenir la compatibilité avec toutes les VM et évitent donc de telles astuces, et utilisent la méthode de réflexion officiellement prise en charge Class<T>.newInstance()
nécessitant un constructeur sans argument.
Pour info : Le constructeur n'a pas besoin d'être public. Il peut avoir une visibilité de package et Hibernate devrait setAccessible(true)
sur elle.
Suis-je capable de créer un UserType personnalisé avec un constructeur non par défaut afin de définir un champ nécessaire pour ses opérations.
A titre de référence ObjectInputStream
fait quelque chose du genre sun.reflect.ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToGetInstanceOf, Object.class.getConstructor()).newInstance()
pour l'instanciation d'objets sans constructeur par défaut (JDK1.6 pour Windows)
Hibernate instancie vos objets. Il doit donc être capable de les instancier. S'il n'y a pas de constructeur no-arg, Hibernate ne saura pas que l'objet a été instancié. comment pour l'instancier, c'est à dire quel argument passer.
Le site documentation hibernate dit :
4.1.1. Implémenter un constructeur sans argument
Toutes les classes persistantes doivent avoir un constructeur par défaut (qui peut être non public) afin qu'Hibernate puisse les instancier à l'aide de la fonction Constructor.newInstance()
. Il est recommandé de disposer d'un constructeur par défaut avec au moins la visibilité du package pour la génération de proxy à l'exécution dans Hibernate.
En ce qui concerne la visibilité du constructeur, si vous utilisez JPA v2.0, vous remarquerez que l'attribut JSR-317 dit : Le constructeur sans argument doit être public ou protégé. .
@Bozho hello sir, j'ai un doute sur le fait que si en interne hibernate utilise Constructor.newInstance() pour instancier l'objet, alors comment hibernate définit les valeurs dans les champs sans aucun setters défini ?
Je ne comprends pas pourquoi je vois cet avertissement pour une sous-classe @Embeddable non-privée avec un constructeur public sans argument...
L'hibernate est un cadre 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 les constructeurs - ce que vous aimeriez peut-être ? - à cause de certains problèmes comme
1º Que se passe-t-il si votre classe contient beaucoup de constructeurs ?
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) { ... }
public Person(String name) { ... }
public Person(Integer age) { ... }
}
Comme vous pouvez le constater, vous êtes confronté à un problème d'incohérence car Hibernate ne peut pas savoir quel constructeur doit être appelé. Par exemple, supposons que vous ayez besoin de récupérer un objet Personne stocké
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Quel constructeur Hibernate doit-il appeler pour récupérer un objet Personne ? Pouvez-vous voir ?
2º Enfin, en utilisant la réflexion, Hibernate peut instancier une classe par le biais de son constructeur sans argument. Ainsi, lorsque vous appelez
Person person = (Person) session.get(Person.class, <IDENTIFIER>);
Hibernate instancie votre objet Personne de la manière suivante
Person.class.newInstance();
Ce qui, selon la documentation de l'API
La classe est instanciée comme par une nouveau avec une expression vide liste d'arguments
Morale de l'histoire
Person.class.newInstance();
est similaire à
new Person();
Rien d'autre
C'est de loin la plus excellente description que j'ai trouvée sur cette question. La plupart des réponses que j'avais trouvées utilisaient des termes techniques livresques et personne ne l'expliquait de manière souple comme vous l'avez fait. Bravo à vous et merci !
Cela pourrait bien être le raisonnement de l'équipe Hibernate. Mais en réalité, les problèmes pourraient être résolus (1) en exigeant soit une annotation, soit l'utilisation d'un constructeur autre que celui par défaut s'il n'y a qu'un seul constructeur et (2) en utilisant class.getDeclaredConstructors. Et en utilisant Constructor.newInstance() au lieu de Class.newInstance(). Un mappage approprié en XML/annotations serait nécessaire, avant Java 8, mais c'est tout à fait faisable.
Ok, donc Hibernate crée l'objet à partir du constructeur par défaut, et ensuite il utilise les setters pour les champs. name
et age
? Si non, il utilise un autre constructeur plus tard ?
Dans quelles conditions un private
incorrect ? Je vois java.lang.InstantiationException
même avec un private
pour mon entité JPA. référence .
J'ai essayé une classe sans constructeur vide (mais avec constructeur args) et cela a fonctionné. J'ai obtenu l'INFO d'hibernate "INFO : HHH000182 : No default (no-argument) constructor for class and class must be instantiated by Interceptor", mais il n'y avait pas d'exception et l'objet a été reçu avec succès de la base de données.
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 poserait pas de problème, vous conviendrez que c'est plutôt bizarre.
La construction d'objets comme le fait Hibernate (je crois qu'il invoque le constructeur à 0 argument, puis modifie probablement les champs de l'instance directement via Reflection. Peut-être sait-il comment appeler les setters) va un peu à l'encontre de la façon dont un objet est censé être construit en Java - invoquer le constructeur avec les paramètres appropriés pour que le nouvel objet soit celui que vous voulez. Je pense que l'instanciation d'un objet et sa mutation sont en quelque sorte " anti-Java " (ou je dirais, anti-Java théorique pur) - et il est certain que si vous le faites via la manipulation directe des champs, cela va à l'encontre de l'encapsulation et de tous ces trucs d'encapsulation fantaisistes.
Je pense que la bonne façon de faire serait de définir dans le mapping Hibernate comment un objet devrait être instancié à partir des informations de la ligne de base de données en utilisant le constructeur approprié... mais cela serait plus complexe - ce qui signifie qu'Hibernate serait encore plus complexe, le mapping 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 de se sentir bien de faire les choses "de la bonne façon").
Cela dit, et vu que l'approche d'Hibernate n'est pas très "propre", l'obligation d'avoir un constructeur à 0 argument n'est pas strictement nécessaire, mais je peux comprendre quelque peu cette exigence, même si je crois qu'ils l'ont fait pour des raisons purement "appropriées", alors qu'ils se sont éloignés de la "bonne méthode" (bien que pour des raisons raisonnables) bien avant cela.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
12 votes
Pour info : l'affirmation selon laquelle
The no-argument constructor is a requirement
c'est faux et toutes les réponses qui expliquent pourquoi il en est ainsi sans se demander si c'est bien le cas (y compris la réponse acceptée, qui a même reçu une prime). ont tort . Voir cette réponse : stackoverflow.com/a/29433238/7731132 votes
Il est nécessaire si vous utilisez Hibernate comme fournisseur pour JPA.
1 votes
@MikeNakis Vous avez tort, Mike. Hibernate a besoin d'un constructeur par défaut pour instancier les objets si vous utilisez Hibernate comme fournisseur pour JPA (Amalgovinus), sinon Hibernate signalera
Caused by: org.hibernate.InstantiationException: No default constructor for entity: : hibernate.tutorial.Student
comme dans le cas que je viens de rencontrer0 votes
@Mushy la question est étiquetée avec "hibernate" et "orm", elle n'est pas étiquetée avec "jpa". Il n'y a aucune mention de JPA dans la question.
2 votes
@MikeNakis Je suis d'accord Mike mais Hibernate est utilisé comme une implémentation de "JPA" et non pas utilisé en l'absence de "JPA" ou "ORM". Par conséquent, l'hypothèse est qu'Hibernate implémente "JPA".