JUG Summer Camp 2010 : JDuchess et Hibernate (3/5)

Et voici le troisième épisode de mes aventures au JUG Summer Camp de La Rochelle !

JDuchess

Après un magnifique buffet froid offert par SERLI, le sponsor de l’événement, il était temps de revenir aux choses sérieuses. Avant la reprise des conférences techniques, une nouvelle Keynote était organisée sur JDuchess. JDuchess est un JUG féminin provenant des Pays Bas. La section française de cette organisation a été créée en début d’année 2010.
L’objectif de JDuchess est assez simple : construire une communauté où les femmes faisant du Java peuvent se rencontrer et partager leurs expériences, leurs points de vue. Elles souhaitent monter un réseau social pour rendre les femmes plus “visibles” et aussi les aider à participer à des événements (i.e.. pas toujours facile de se motiver si on est la seule fille…).
Le bilan que j’ai tiré de cette présentation, c’est que JDuchess ne doit pas être perçu comme une “ségrégation” mais comme une façon de faire tomber les préjugés ! Et attention, JDuchess n’est pas du tout réservé aux femmes.

Resources

Hibernate

Emmanuel Bernard est le leader des projets Hibernate Validator et Hibernate Search, membre de l’Expert Group JPA 2.0 et Spécification Leader sur la JSR 303. Il est également l’auteur du livre Hibernate Search in Action. Quand il lui reste quelques heures à perdre, il anime aussi un podcast dédié aux technologies Java : lescastcodeurs.com 🙂

Sa présentation avait deux objectifs : effectuer un tour d’horizon des nouveautés sur Hibernate Core (i.e.. l’ORM) ainsi que sur les projets périphériques, développés par JBoss, autour de ce module.

Évidemment, la plus grosse nouveauté de la version 3.5 d’Hibernate Core, c’est le support du standard JPA 2.0. Cela représente environ 2/3 ans de boulot : une phase de “standardisation” via le JCP puis d’implémentation dans Hibernate (exemple : remplacement des annotations spécifiques d’Hibernate par celles de JPA2), puis enfin, le passage du test de compatibilité (le fameux TCK).

Études de cas

Emmanuel nous présente ensuite plusieurs petites nouveautés de la version 3.5.x d’Hibernate.

  • @MapsId : une annotation qui permet de “copier” l’identifiant d’une entité pour en faire la clef d’une autre (Exemple : lien Customer > User). C’est un besoin assez fréquent, que je suis heureux de voir couvert en standard !

  • @GenericGenerator : Générateurs d’identifiants de type UUID, séquence, auto-increment, etc.… Les générateurs ne sont pas nouveaux, mais ils peuvent désormais être utilisés pour générer une portion de l’identifiant (une portion de clef primaire par exemple). Le paramètrage se fait via @GenericGenerator(strategy=“uuid2”)

  • Column R/W qui permet d’appliquer des fonctions (PL/SQL ?) lors de l’accès à la BDD.  Il n’est pas (encore) possible de le faire par des annotations, il faut passer par la configuration XML d’Hibernate

  • @FetchProfile : depuis le démarrage d’Hibernate, il est possible de définir la stratégie de chargement des collections liées sur un objet. Cela passait toujours par la déclaration en mode EAGER / LAZY sur chaque association. Maintenant, il est possible de “pré-configurer” plusieurs stratégies de chargement puis de les activer au runtime. Exemple :

session.enableFetchProfile(“all”) [requetes] session.disableFetchProfile(“all”)

Criteria API

Une grosse nouveauté (amenée par le passage à JPA2) est la nouvelle API de création de requête. Il s’agit d’une API orienté objet (le contraire de JDBC) et statiquement typée (i.e.. à la compilation). Emmanuel, nous explique comme fonctionne le typage fort de cette API. Prenons le code suivant :

EntityManager em; CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = qb.createQuery(Order.class); //select c from Customer c join fetch c.orders cq.from(Customer.class).fetch(Customer_.orders, INNER); TypedQuery q = em.createQuery(cq); List orders = q.getResultList();

Ca semble être presque magique : on obtient une List d’Order et on paramètre le fetch sur l’association orders. En fait, Hibernate va généré un méta-modèle depuis vos objets via la description des entités (XML ou annotations). Ce méta-modèle est généré par votre IDE, par un plugin Maven ou bien un outil dédié. L’énorme avantage de cette approche via API comparativement à l’écriture de JP-QL, c’est que si on fait un changement dans le modèle de données, cela impacte le méta-modèle et entraîne donc des erreurs de compilation (ou bien un refactoring automatique !)

Emmanuel a ensuite fait un petit rappel des problématique courante que l’on rencontre dans une application massivement parallèle lorsque l’on utilise une base de données conjointement avec Hibernate :

  • Dirty Reads : Une transaction A a modifié une ligne, mais n’a pas commité ses changements. Une transaction B lit les mêmes données que A mais sa vision des données peut être fausse si A annule ses changements mais que B a déjà effectué son propre commit.
  • Non-repeatables read : Une transaction lit une ligne deux fois mais lit des données différentes à chaque fois car un traitement externe est en cours sur la base de données

Hibernate propose plusieurs réponse à ces problématiques :

  • Optimistic (Hibernate + JPA) : on utilise un numéro de version sur chaque ligne afin de détecter les changements de type Dirty Reads. A employer lorsque les problèmes de concurrence d’accès sont très épisodiques
  • Pessimistic Read / Write : utilise les appels natifs SQL LOCK TABLE de façon explicite. A utiliser lorsque les problèmes de concurrence d’accès sont considéré comme une véritable erreur applicative

Autre nouveauté de cette version 3.5 d’Hibernate c’est le support d’une nouvelle implémentation du cache de second niveau. EhCache peut ainsi être remplacé par le nouveau Infinispan. Emmanuel présente Infinispan comme la V2 de JBoss Cache, alliant bonnes performances en cache local ainsi qu’une conception massivement distribuée. Je vous laisse découvrir le reste sur ce très bon article de Chrisophe : DataGrid Infinispan : Oracle Coherence en version Open Source ?

Hibernate Search

Hibernate Search est un moteur d’indexation et de recherche full-text basé sur Apache Lucene. Il prend en charge la gestion d’un index Lucene et sa synchronisation avec une structure objet persistée en base de données. Il permet de simplifier l’indexation (utilisation de simples annotations sur les objets du modèle) ainsi que l’écriture de requête.

En effet, l’écriture de requête Lucene n’est pas toujours évidente : depuis la version 3.3.x de Hibernate Search, il est possible d’utiliser une nouvelle API QueryBuilder. Cette API utilise une approche “langage naturel” pour l’écriture des requêtes :

QueryBuilder mythQB = searchFactory.buildQueryBuilder().forEntity(Myth.class).get(); Date twentiethCentury = ...; Query luceneQuery = mythQB .bool() .must( mythQB.keyword().onField("description_stem") .matching("urban").createQuery() ).createQuery();

Hibernate Envers

Emmanuel a ensuite présenté un projet de la galaxie Hibernate que je ne connaissais pas du tout. Il s’agit de Hibernate Envers qui est un système de gestion de données d’audit (aussi appelée historisation). C’est une demande récurrente dans de nombreux projets d’informatique de gestion : “dites-moi qui a modifié tel données et quand ?”

Envers s’intègre très facilement dans des entités Hibernate existantes. Son activation se fait en deux phases :

  • Ajout de l’annotation @Audited sur les entités que l’on souhaite versionner
  • Ajout de Hibernate Envers dans le classpath

Pour fonctionner, il crée une nouvelle table (en complément de la table de stockage habituelle d’Hibernate), préfixée par _AUD.
Hibernate Envers permet ensuite de naviguer dans les données d’audit via deux mécanismes orthogonaux :

  • Permet de charger un objet dans une ancienne révision (et conserve la navigation entre entités)
  • Requête sur l’historique (permet de détecter quand un champ a été modifié)

Il est dans le TOP10 des projets que je compte essayer rapidement !

Hibernate Validator

Hibernate Validator est un framework qui permet de définir des contraintes sur les objets du modèle (via XML ou annotations), de valider ses contraintes dynamiquement et de récupérer les erreurs de validation. Il s’agit de l’implémentation de référence (RI) de la JSR 303.

Voici un exemple simpliste de validation d’une entité :

@Entity public @CustomerNumber @NotNull public String getCustomerNumber() { return customerNumber }; }

Hibernate Validator 4.1 peut maintenant profiter du méta-modèle généré sur les entités JPA. Cela permet notamment de détecter lors erreurs de configuration au plus vite (Emmanuel donne l’exemple d’une contrainte du type @Size sur un champ Date qui n’a pas sens et va générer une erreur du compilateur).

Il est bien sûr possible d’implémenter ses propres validateurs, d’utiliser des méta-contraintres (définition d’une contrainte personnalisé comme la composition de plusieurs contraintes existantes) ou encore de regrouper les contraintes par groupe (ce qui permet de ne valider que certains groupes)

Hibernate Validator peut être intégré dans la validation d’IHM (JSF, Wicket, GWT ou GraniteDS pour Flex), pour la validation des entités via JPA ou encore la création de contraintes en base de données via Hibernate Core

Resources

La suite demain avec “La Forge Logicielle” selon Nicolas De Loof !