You are browsing the archive for Développer.

EclEmma et Hibernate Tools

10:00 am in Développer by Blandine

J’ai découvert récemment deux plugins Eclipse assez pratiques :

  • EclEmma : il permet d’avoir instantanément la couverture de code,
  • Hibernate Tools : il offre plusieurs fonctionnalités qui aident à l’écriture des requêtes en Criteria ou HQL.

EclEmma est un plugin libre pour Eclipse qui se base sur l’outil d’analyse de couverture de code EMMA. Il intègre les fonctionnalités d’EMMA directement dans le workspace d’Eclipse.
Ce plugin s’installe en quelques cliques et ne nécessite pas de configuration particulière. De plus, il est non invasif (il ne rajoute pas des fichiers partout).
Pour l’utiliser, il suffit de lancer les tests unitaires en mode « coverage » (bouton dans Eclipse coverage). À chaque lancement, une session est créée. Celle-ci peut être sauvegardée et importée plus tard.
Les résultats de l’analyse sont les suivants :

  • une vue d’ensemble de la couverture sous forme d’arborescence du code du projet à la méthode,
  • la possibilité d’avoir les résultats par nombre de ligne de code, bloc, méthode, classe …
  • une coloration du code (vert : ligne totalement couverte, jaune : ligne partiellement couverte et rouge : ligne non couverte).

EclEmma offre aussi la possibilité d’exporter les résultats sous forme de rapport dans les formats HTML, XML ou TXT.

Eclipse : EclEmma - vue coverage

Eclipse : EclEmma - vue Coverage

Hibernate Tools est développé par JBoss : c’est une composante de JBoss Tools. Il existe sous forme de plugin pour Eclipse et de tâche pour Ant et fait aussi parti de JBoss Developper Studio.
Le plugin pour Eclipse contient plusieurs fonctionnalités :

  • Mapping Editor : en plus de la coloration et l’auto-complétion que l’on a par défaut dans Eclipse, cet éditeur fournit l’auto-complétion dans les fichiers de configuration Hibernate sur les noms de classes et d’attributs des objets domaines et les noms de tables et de colonnes de la base de données.
  • Console : après configuration, cette vue permet de visualiser le mapping entre les objets domaines et la base de données, d’avoir un éditeur de requête en HQL et en Criteria.
  • Reverse Engineering : c’est la fonctionnalité la plus puissante d’Hibernate Tools. À partir d’une base de données, il est possible de générer les fichiers de mapping, les objets domaines, la couche DAO, la documentation …

La suite de ce post portera uniquement sur la Console Hibernate. Elle correspond à la perspective « Hibernate » dans Eclipse.
Après avoir installé le plugin dans Eclipse, il faut configurer la connexion à la base de données, le fichier de configuration Hibernate et le projet où se trouve les objets domaines.
Attention, si le fichier de configuration Hibernate contient l’élément class-cache, on obtient une exception Hibernate : org.hibernate.HibernateException: Could not instantiate cache implementation. Pour contourner ce problème, j’ai créé un fichier de configuration Hibernate sans les éléments class-cache.
La Console ne prend pas les changements à la volée, en cas de modification des fichiers de mapping ou des objets domaines, il faut penser à recharger la configuration.
La perspective console contient quatre vues principales :

  • la vue configuration,
  • l’éditeur HQL,
  • l’éditeur Criteria,
  • la vue propriétés.

La vue configuration est composé de trois sous parties : configuration (mapping), session factory (objets domaines) et database (base de données). L’utilisateur peut explorer ces trois parties ; on retrouve les attributs/colonnes, ainsi que les types de données. En sélectionnant un élément de la configuration, il est possible d’éditer la classe Java ou le fichier de mapping correspondant ou d’ouvrir l’éditeur de requête HQL/Criteria contenant la requête de sélection de cet élément.

Eclipse : perspective Hibernate

Eclipse : perspective Hibernate

L’éditeur HQL est très pratique pour développer et débugger du HQL :

  • saisie des paramètres dans la vue Query Params,
  • traduction dynamique de la requête en SQL (Hibernate Dynamique SQL Preview),
  • affichage des résultats (Hibernate query Result), ainsi que la possibilité d’explorer les objets dans la vue propriétés.

L’éditeur Criteria offre juste la possibilité d’exécuter les requêtes. Pour les deux éditeurs de requêtes et à chaque édition de requêtes, on obtient le temps d’exécution et le nombre de résultats.

Merci à David de m’avoir fait découvrir ces deux plugins.
Merci à Ellène et Victor pour la relecture.

Hibernate un ami qui vous veut du bien ?

11:49 am in Développer by Blandine

Cet article est un retour d’expérience sur la mise en place d’une pagination dans un écran de recherche contenant un filtre composé de deux listes déroulantes. Hibernate fonctionne avec la majorité des SGBD. Toutefois, ceux-ci n’offrent pas tous les mêmes fonctionnalités. Le SQL natif généré par Hibernate sera différent selon les SGBD. Nous verrons en quoi cela peut poser problème.

Ce cas s’appuie sur une application utilisant Hibernate et Sybase ASE 12.5. L’écran à développer, en plus de la pagination, possède un filtre facultatif. La clause where étant dynamique, je décide d’utiliser les Criteria pour écrire ma requête.  Il y a dans le manuel Hibernate une section dédiée à la pagination. Elle vous conseille d’utiliser les méthodes setFirstResult et setMaxResults de l’interface Query en précisant qu’Hibernate sait comment traduire ceci en SQL natif adapté à votre SGBD.

J’implémente ma dao et je filtre le résultat renvoyé :

Criteria crit = session.createCriteria(Flux.class);
//ajout des restrictions – filtre utilisateur
List result = crit.setFirstResult(firstResult)
            .setMaxResults(nbRows).list();

J’écris mon test unitaire, je réalise quelques tests sur ma base de données de test, je « commit ». Voilà, c’est fini !

Quelque temps plus tard, le chef de projet souhaite faire des tests en pré-qualification sur un nombre de lignes conséquent (il est vrai que tester la pagination quand il n’y a qu’une seule page ce n’est pas très drôle). La pagination fonctionne sur les premières pages, mais impossible d’afficher la dernière page sans faire tomber l’application. Le message d’erreur suivant est très explicite :

<10 juin 2010 15 h 20 CEST> <Critical> <Health> <BEA-310003>
<Free memory in the server is 4 122 880 bytes. There is danger of OutOfMemoryError>
Exception in thread "[ACTIVE] ExecuteThread: '18' for queue: 'weblogic.kernel.
Default (self-tuning)'" java.lang.OutOfMemoryError: Java heap space

...
The exception message is - Java heap space
java.lang.OutOfMemoryError: Java heap space

En regardant le code SQL généré par Hibernate, on remarque qu’il n’y a pas de filtre pour la pagination. Malheureusement, Sybase possède moins de fonctionnalités que d’autres SGBD et ne connaît pas les mots clef « LIMIT » ou « ROWID » et de ce fait, le setFirstResult et setMaxResults ne sont pas traduits en SQL natif. Hibernate est donc obligé de tout récupérer dans sa requête et de faire le filtre de pagination côté java. Il charge les objets en mémoire tant qu’il n’a pas les résultats souhaités pour la page demandée. Cela ne pose pas de problème pour les premières pages, mais lorsqu’on veut atteindre la dernière page, la consommation mémoire explose.

Utilisation de la mémoire - schéma de JConsole

Figure 1 – Utilisation de la mémoire – schéma de JConsole

Ainsi, nous ne pouvons pas utiliser l’interface Query dans ce cas. Cette version de Sybase ne supporte pas non plus les sous requêtes ordonnées. La seule solution que nous avons trouvée est de faire la  requête en deux temps : d’abord sur les identifiants, puis récupérer les données  à partir de ceux-ci.

Cette solution peut s’implémenter de deux façons :

  • Solution 1 : récupérer la liste des identifiants filtrées par Hibernate (même code qu’au début, mais en ne retournant que les identifiants) ;
  • Solution 2 : obtenir la liste de tous les identifiants, puis la filtrer en utilisant la méthode subList de l’interface List.

Nous avons testé les deux solutions. En observant l’utilisation de la mémoire, la solution 2 semble plus performante.

img2-solution1

Figure 2 – utilisation de la mémoire pour la solution 1

Utilisation de la mémoire pour la solution 2

Figure 3 – utilisation de la mémoire pour la solution 2

Pour finir, on a une première requête écrite avec les Criteria qui permet de récupérer tous les identifiants en fonction des filtres de l’utilisateur. Puis, on crée une sous-liste pour ne garder que les id correspondant à la page demandée. On fait une dernière requête en HQL pour récupérer les objets.

Criteria crit = session.createCriteria(Flux.class);
//ajout des restrictions – filtre utilisateur

List lsId = crit.setProjection(
           Projections.property("id")).list() ;

List result = null;

if ( lsId != null &amp;&amp;  lsId.size()&gt;0) {
	//si la liste d'id est vide, la requête hql plante
	Query q = getSessionFactory().getCurrentSession().getNamedQuery(
      		"getListFluxByIds").setParameterList(
	      "idList",
	      lsId.subList(firstResult,
	      lastResult));

	result = (List) q.list();
}

A retenir :

Hibernate est votre ami, mais il ne peut pas être plus fort que votre SGBD. Il est donc utile de vérifier le code SQL natif qu’il génère.

Concernant Syabse ASE 12.5, on espère que les versions futures supporteront les fonctions liées à la pagination.

Je remercie David, Ellène et Victor pour la relecture et les conseils sur WordPress.