How to retrieve the Hibernate Session from the EntityManager interface
Par batmat le dimanche 13 juillet 2008, 23:42 - Technique - Lien permanent
Well, as I myself fell into this stupid gap, I guess I'll try to help. I was quite pushed in this trap by a fallacious part of the jboss documentation :
@PersistenceContext EntityManager entityManager;
public void someMethod();
{
org.jboss.ejb3.entity.HibernateSession hs = (HibernateSession)entityManager;
org.hibernate.Session session = hs.getHibernateSession();
}
Let's be clear : this is totally WRONG! Yes, it will work under JBoss, but as there's a standard way to do this, this is not the right way to do this.
In fact, there's a dedicated method that lets you retrieve the underlying persistence manager : EntityManager.getDelegate(). If you read this method's javadoc, you'll see the following :
/**
* Return the underlying provider object for the EntityManager,
* if available. The result of this method is implementation
* specific.
* @throws IllegalStateException if this EntityManager has been closed.
*/
public Object getDelegate();
And the "underlying provider", for Hibernate, is obviously the Hibernate Session instance...
So, the right way to retrieve the Session is something like the following instead :
@PersistenceContext EntityManager entityManager;
public void someMethod();
{
org.hibernate.Session session = (Session)entityManager.getDelegate();
}
Under JBoss, using this code won't make a big difference. But using the standard way will let you run your code under several appservers (namely, it works like a charm[1] under JBoss 4.2.2.ga and Glassfishv2ur1 for example). If you use the bad way above, this will just crash under Glassfish, for example...
I reported the corresponding documentation bug in the JBOSS tracker.
Hope this helps...
Notes
[1] ça, c'est pour Seb

Commentaires
Tout d'abord je voulais te remercier pour ce blog qui est bien sympathique et, par experience, je sais que ca demande du temps...
Et puis desole pour les accents mais je suis aux US et je n'ai pas d'accents sur le clavier...
Maintenant je voulais juste revenir sur cet article, juste pour m'eclairer un peu tout en esperant ne pas trop me tromper...
Cet article se place dans le contexte de l'utilisation de JPA. Cette API permet de s'abstraire du framework de persistence utilise. Que ce soit Hibernate, JDO, TopLink etc.
Dans un soucis de standardisation et de reutilisation du code je trouve dommage de faire appel a Hibernate dans le code... A partir de la, ile me semble du coup complique de vouloir eventuellement changer de provider de persistence!?
Alors j'imagine que ce choix vient de la necessite d'utiliser des fonctionnalites propres a Hibernate?
Encore bravo pour le blog et a++
> Cette API permet de s'abstraire du framework de persistence utilisé.
Tout à fait.
> Dans un soucis de standardisation et de réutilisation du code je trouve dommage de faire appel a Hibernate dans le code... A partir de la, il me semble du coup complique de vouloir éventuellement changer de provider de persistence!?
En fait, ce besoin est apparu pour moi lors d'une migration de code Spring/Hibernate à EJB3/JPA. Or, nous n'envisageons pour le moment que de migrer la partie "Services", pas le DAO. Injecter directement la Session Hibernate aurait été possible dans JBoss en l'annotant avec l'annotation habituellement utilisée pour l'EM. Le problème, c'est que ça n'aurait alors fonctionné que dans JBoss :-/.
Pour que l'injection fonctionne dans n'importe quel serveur, il faut donc toujours injecter un EntityManager, puis récupérer si besoin la Session Hibernate à partir de cette instance.
Tout à fait d'accord avec toi donc sur le problème si nous voulions changer de provider de persistance, mais :
Si tu commences un nouveau projet, il me semble effectivement mieux d'arriver à rester full-JPA, à plus fortes raisons parce que JPA2 arrive
participation un peu tardive, mais bon...
org.hibernate.Session session = (Session)entityManager.getDelegate();
La méthode getDelegate retourne un objet, rien ne garantit donc que le cast fonctionne dans tout les cas de figure, cela dépend donc du serveur d'appli, en conséquence ce code n'est pas portable sur toutes les plateformes. A confirmer, JBoss ne retourne pas une session hibernate mais un objet wrapper.