12
votes

Hibernate 4 ClasscastException sur le chargement paresseux tandis que l'averse fonctionne bien

J'ai les suivantes Entité racine de l'héritage joincière pour les zones géographiques (comme des continents, des pays, des états, etc.): xxx pré>

Comme vous pouvez le voir une zone d'auto-identification unique. Pk, un nom et une relation avec son parent (référence auto). Veuillez faire attention à la relation parent code> géo mappée comme fetchtype.lazy code>. Dans la DB, le parent_id code> est non null code> rendant la relation en option. La valeur par défaut pour @manytoone code> est en option = true code>, de sorte que les mappages semblent être corrects. P>

Les sous-classes définissent des propriétés supplémentaires et ne sont pas de intérêt vraiment. Les données de la base de données sont correctement liées car les zones GEO peuvent être répertoriées sans problèmes via JPQL (avec un fetchtype.eager légèrement différent Code> Mappage sur Parent code>, voir Fin du texte) : p>

liste Arena avec chargement impatient p>

Chaque ligne est une Instance de: p> xxx pré>

Lors de la requête de liste avec le parent mappé comme paresseux, je reçois l'exception suivante: p> xxx pré>

L'imprimeur avant la trace de la pile est la suivante: p>

13:57:47,245 INFO  [stdout] (http--127.0.0.1-8080-4) arena = Joachim-Schumann-Schule: using club's district parent = com.kawoolutions.bbstats.model.State@2b60693e[id=258,name=Hesse,isoCode=HE,country=com.kawoolutions.bbstats.model.Country@17f9976b[id=88,name=Germany,isoCode=DE,isoNbr=276,dialCode=<null>]]


0 commentaires

3 Réponses :


19
votes

Le problème avec le chargement paresseux est que Hibernate générera de manière dynamique des proxies pour des objets paresseusement chargés. Pendant d'abord, cela semble être une bonne idée de mettre en œuvre le chargement paresseux, un développeur doit être conscient du fait qu'un objet peut être un proxy hibernate. Je pense que c'est un bon exemple d'abstraction fuite. Dans votre cas, la valeur de retour de l'appel di.getparent () est un objet de proxy, généré à travers la bibliothèque Javassist utilisé par Hibernate.

Ces proxy d'hibernation entraîneront des problèmes liés à des mises, d'instanceOf et d'appels vers égaux () et hashcode () Si vous n'avez pas mis en œuvre ces méthodes de votre entité .

lire Cette question et cette réponse indique comment utiliser l'interface de marqueur HibernateProxy Pour convertir un proxy en objet réel. L'autre option est d'aller avec le chargement impatient dans ce cas.

Au fait, réfléchissez à la fossé que "Notation hongroise"; -)

édité pour répondre aux questions du commentaire:

existe-t-il une voie portable (JPA) pour y parvenir?

pas que je sache. Je résumés la logique de conversion de l'autre Qa à l'extérieur derrière une interface et fournissez une autre implémentation noop en utilisant JBoss 7 et CDI, vous pouvez passer à celui-ci sans même recompiler.

peut-il être automatisé?

Il pourrait être possible d'utiliser AspectJ. Vous pouvez essayer d'écrire un autour de conseils pour tous les appels de getters sur vos entités qui renvoient d'autres entités. Le conseil vérifiera si le champ sous-jacent est un proxy hibernate et, dans l'affirmative, appliquez la conversion, puis renvoyez le résultat de la conversion. Ainsi, vous obtiendrez toujours l'objet réel lorsque le getter est appelé mais pourrait toujours bénéficier de chargement paresseux. Vous devriez tester cela à fond, bien que ...


1 commentaires

Y a-t-il une voie portable (JPA) pour y parvenir? Peut-il être automatisé?



0
votes

Vous utilisez jboss avec les chargeurs de modules.

La raison principale d'un ClasscastException avec des proxies est que Le proxy (généré par hibernate ) utilise une instance différente de la classe d'état comme appelant (client). Il doit y avoir deux instances de votre classe d'état dans le même Java JM! jboss gère avec des modules et des dépendances impitoyables / exportations / exportations entre modules.

Vous devez donc vérifier votre Modules d'application Ou utilisez un autre serveur d'applications avec chargement de classe standard.


0 commentaires

3
votes

Peu de choses pour étendre Robert Petermeier Répondre. Pour cette construction: xxx

car geoarea.parent est un proxy paresseux, créant ce proxy hibernate ne sait pas ce qui sera la classe réelle chargée dans ce champ. Il connaît seulement qu'il sera de Geoarea Sous-classe. Donc, cela crée une proxy javaassist à Geoarea Classe qui ne sera jamais istable à État ou à tout sous-type différent de Geoarea .

Donc, vous pouvez déballer de manière proxy pour chaque d'une instance de d'utilisation ou de type de moulage, mais ce n'était pas une option pour moi (j'ai fabriqué des associations de lots paresseux dans un grand système pour améliorer la performance de la base de données - être 100 % sûr si le système fonctionne toujours, j'aurais besoin d'ajouter du déballement partout, je peux voir le type Cast ou instance de ). Mais vous avez une option pour l'automatiser en utilisant Instrumentation Bytecode .

Enfin, j'ai trouvé une solution transparente pour éviter l'instrumentation Bytecode - dans l'énorme système, nous ne saurions toujours pas ce qui ne fonctionne plus après avoir ajouté cette instrumentation, ainsi que après avoir ajouté du code déballé manuellement :) Vous pouvez appliquer un truc simple pour déballer le proxy manuellement dans le getter. Voici mon exemple: xxx

et ici sont des explications plus détaillées sur le problème.


0 commentaires