Utilisez Hibernate 4.3 sous JBoss 5 avec Spring 4

logo-hibernateDans mon précédent billet, je vous expliquais comment réintroduire le support de VFS 2 abandonné dans Spring Framework 4.0. Et ceci, dans l’optique de pouvoir déployer mon application dans le serveur d’application JBoss 5.1 EAP.
Outre ce problème survenant lors de la détection de beans Spring dans le classpath, la montée de version de Spring 3.2 à Spring 4 a révélé un autre problème lié au format VFS de JBoss.  Cette fois-ci, c’est le framework Hibernate 4.3 qui n’arrive pas à détecter les entités JPA du classpath.

Certifié conforme à Java EE 5, JBoss 5.1 EAP utilise Hibernate 3.3 comme implémentation de JPA 1.  Dans mon cas, Hibernate 4.3 est utilisé en mode standalone et est donc directement embarqué dans les librairies de mon EAR. La configuration JPA 2.1 est assurée par le support JPA offert par Spring, et plus particulièrement par la classe LocalContainerEntityManagerFactoryBean.

Problème rencontré

Au démarrage de l’application, Hibernate s’appuie sur l’interface Scanner pour détecter les classes, les packages et les ressources d’une Unité de Persistance JPA. L’implémentation StandardScanner délègue le parcours du WAR à la classe StandardArchiveDescriptorFactory. Ligne 72 de cette dernière, l’appel à la méthode file.exists() échoue sur le chemin « vfszip:/C:/jboss-eap-5.1/server/default/deploy/myapp-ear-1.0.0-SNAPSHOT.ear/myapp-war-1.0.0-SNAPSHOT.war/WEB-INF/classes/ ». Une IllegalArgumentException est levée :

 Solution

Comme précisé en introduction, notre application utilise la fabrique de beans LocalContainerEntityManagerFactoryBean pour créer l’EntityManagerFactory de JPA. Lors de la configuration de ce bean, la méthode setPackagesToScan permet d’indiquer à Spring quel package Java il doit scanner au démarrage de l’application pour détecter les entités JPA. Spring utilise alors le même mécanisme d’auto-détection que pour les beans Spring et scanne tous les JAR du classpath.
Dans l’exemple ci-desssous, le package com.javaetmoi.demo.model ainsi que tous ses sous-packages sont scannés :

Le support JPA proposé par Spring fait que le fichier pesistence.xml n’a plus de raison d’être. Et vous l’aurez compris, le scan d’Hibernate ait redondant à celui de Spring. Il peut donc être désactivé.

La classe NopScanner disponible sous forme de Gist permet de court-circuiter le scan d’Hibernate :

Indiquer à Hibernate d’utiliser la classe NopScanner revient à déclarer la propriété Hibernate suivante :
hibernate.ejb.resource_scanner=com.javaetmoi.core.persistence.hibernate.NopScanner

En utilisant la syntaxe Java, cette propriété peut être ajoutée dans la méthode additionalProperties() utilisée lors de la déclaration du bean LocalContainerEntityManagerFactoryBean dans l’exemple précédent :

Conclusion

La possibilité offerte par JPA de pouvoir être utilisée en dehors d’un conteneur Java EE ainsi que la souplesse du support JPA proposé par le framework Spring font qu’il est possible d’utiliser JPA 2.1 (introduit ans JEE 7) dans un serveur JEE 5.

Ayant utilisé cette approche dans ce billet, je vous donnerai prochainement un exemple complet de configuration Spring en Java d’une application basée sur Spring MVC et JPA. Restez connectés !!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *