D’ici quelques jours, l’intégralité des vidéos des conférences et universités présentées lors de Devoxx France 2019 sont disponibles sur la chaîne Devoxx FR de Youtube.
Si vous souhaitez rapidement vous faire un avis sur leur contenu avant de les visionner ou si vous souhaitez garder une trace écrite de ce que vous y avez appris, je mets librement à disposition l’ensemble de mes 18 notes prises au cours de ces 3 jours riches en contenus et en découvertes.
Lors de cette édition 2019, les 2 frameworks hypes du moment Quarkus et Micronaut étaient sur le devant de la scène en permettant de développer des applications Java modernes et natives grâce à GraalVM. Poussée par l’essor des microservices, l’intégration de Java à Docker et son orchestrateur Kubernetes est de plus en plus poussée. Les indémodables étaient également de la partie : design d’API REST, montée de version de Java, qualimétrie, JavaEE (oups, pardon, JakartaEE) et sécurité.
Mes notes classées par ordre de préférence :
Dans ce billet, je vais donc vous expliquer comment créer votre propre usine logicielle. Déployée à cheval sur GitHub et l’offre DEV@Cloud de CloudBees, vous y retrouverez les briques les plus classiques : SCM, intégration continue, dépôt de binaires, bug tracker, wiki …
Le gain : à chaque commit poussé dans GitHub, votre code est compilé, testé unitairement puis déployé dans un repository maven public dédié aux Snapshots. Par ailleurs, vous pourrez effectuer des releases maven en local depuis votre poste de développement ; les artefacts construits seront mis à disposition dans un repository maven dédié. Tout développeur pourra librement référencer l’un ou l’autre de ces repository et utiliser votre code.
En bonus, si vous développez des projets open source, vous n’aurez même pas à sortir votre carte bancaire.

Le tableau ci-dessous liste les différentes briques de l’usine de développement ainsi que les motivations qui m’ont poussé à les choisir.
| Brique de l’usine logicielle | Outil | Plateforme | Raisons |
| Gestionnaire de Code Source (SCM) | Git | GitHub | Pour utiliser la pleine puissance de Git, bridé jusque-là par l’utilisation en entreprise du bridge git-svn. |
| Outil de build | Maven | Poste de Dev + Cloudbees |
L’incontournable maven. Mais cela aurait pu être l’occasion de tester Gradle. |
| Intégration Continue | Jenkins | CloudBees | Un comble : probablement celui que je connaissais le moins par rapport à Continium, Bamboo et TeamCity. |
| Dépôt de binaires | Repository Maven | Cloudbees | Offre de base de CloudBees suffisante. Accès par webdav |
| Espace documentaire | Wiki | GitHub | Pages versionnées avec Git Syntaxte MarkDown Le XWiki de CloudBees aurait pu être une alternative |
| BugTracker | Navigateur Web | GitHub | Projets OSS personnels pas suffisamment actifs pour bénéficier d’un Jira (ni même d’une licence JRebel) |
Afin de vous donner une idée du résultat, je vous invite à jeter un coup d’œil aux différentes URLs :
2 prérequis sont nécessaires au déploiement d’une telle usine de développement :
Afin de pouvoir intégrer un projet mavenisé dans l’usine de développement, il est préalablement nécessaire de compléter sa configuration maven pour prendre en compte :
Toute cette configuration est détaillée dans un précédent billet intitulé Release Maven sous Windows d’un projet GitHub déployé sur CloudBees. Vous y trouverez notamment comment configurer les différentes balises maven au travers 2 fichiers :
Gage de son intérêt, le projet github maven-config-github-cloudbees à l’origine de l’article a été forké par Ryan Cambell et est désormais proposé dans la Cloudbees Community de GitHub.
Une fois le pom.xml commité dans GitHub avec le reste du code source, le build Jenkins correspondant peut être configuré.
Depuis la console d’administration de Jenkins, vérifier que le Jenkins GIT plugin soit installé puis installer le GitHub plugin.
Dans la section CloudBees DEV@Cloud Authorization, configurer l’URL du chemin d’accès au repository Github qui sera utilisée par le plugin GitHub:
Dans la section Gestion de code source du build Jenkins, sélectionner l’option Git Repositories puis renseigner le Repository URL.
La syntaxe à utiliser est la suivante : https://github.com/<username>/<repository name>.git
Exemple : https://github.com/arey/hibernate-hydrate.git

Afin que Jenkins lance le build lors de la réception d’un hook en provenance de GitHub, sélectionner la case Build when a change is pushed to GitHub dans le panneau ci-dessous :

La version de maven, le chemin vers le pom.xml racine ainsi que le goal à exécuter peuvent être configurés dans la section Build :

Lorsqu’aucun goal n’est précisé, Jenkins exécute un install.
A la fin du build, on indique à Jenkins de déployer les artefacts dans le repository CloudBees des Snapshots :
![]()
Afin d’exploiter au mieux le plugin GitHub de Jenkins et laisser Jenkins configurer les hooks dans GitHub, il est possible de renseigner votre login / mot de passe dans l’encart GitHub Web Hook accessible depuis le menu Administration Jenkins > Configurer le Système.

Dernière étape de la mise en place de notre usine de développement : la configuration de GitHub.
Pour que Jenkins soit notifié à chaque push dans GitHub et relancer ainsi le build maven configuré précédemment, il est nécessaire de configurer un Hook web dans GitHub.
La WebHook URL doit référencer votre forge logicielle CloudBees.
Syntaxe : https://<cloudbees username>.ci.cloudbees.com/github-webhook/
Exemple : https://javaetmoi.ci.cloudbees.com/github-webhook/

Cette configuration n’est a priori pas nécessaire si vous utilisez le plugin GitHub Jenkins. Ce dernier se charge en effet d’ajouter les WebHooks pour vous.
Pour que CloudBees ait les habilitations nécessaires pour accéder à l’ensemble de vos repository GitHub, sa clé publique doit être ajoutée dans la partie SSH Keys accessible via le menu d’administration de GitHub :

En principe, si je n’ai rien omis de mentionner dans ce guide, tout est prêt. Et pour vérifier que votre usine de développement est opérationnelle, vous avez le choix entre :
Suivant CloudBees depuis son lancement il y’a plus de 2 ans, j’ai eu la chance de pouvoir bénéficier début 2012 de l’offre gratuite Free and Open-Source Software. Après avoir passé un peu de temps au départ pour mettre en place mon usine, j’en suis aujourd’hui pleinement satisfait et je serais prêt à l’expérimenter en entreprise.
N’ayant utilisé qu’une infime partie des services proposés par CloudBees, de nombreuses découvertes s’offrent encore à moi : utiliser le plugin release de Jenkins, tester SauceLabs ou bien encore déployer une application web sur la plateforme RUN@CloudBees.
Apparu quelques mois après mes débuts sur DEV@cloud, CloudBees propose le produit BuildHive aux développeurs utilisant GitHub et qui souhaitent mettre en place de l’intégration continue sur leur projet. Non seulement ce produit est gratuit, mais il simplifie considérablement la configuration de votre build, à la fois côté Jenkins que côté GitHub grâce au protocole OAuth. Tout est automatisé. Je me suis inscrit et j’ai créé mon premier build en à peine 2 minutes. Un hook sur les pull request permet même de lancer un build afin de valider le code soumis. Néanmoins, il y’a tout de même quelques limitations par rapport à la solution que vous ai proposée : pas de repository maven, impossibilité d’installer des plugins Jenkins … A vous de décider lequel vous convient !
]]>
Habitué aux releases maven avec SVN, j’ai rencontré quelques difficultés pour effectuer la première release du projet Hibernate Hydrate [1] hébergé sur GitHub et présenté dans un précédent billet.
Pour rappel, lors d’une release, le plugin maven accède au gestionnaire de code source pour commiter les modifications effectuées sur les pom.xml et créer un tag. Il déploie ensuite les artefacts sur le repo maven distant.
Mes contraintess techniques étaient les suivantes :
Les réponses apportées par ce billet sont :
Pour permettre à maven d’accéder en lecture et en écriture à votre repo GitHub, vous devez tout d’abord configurer comme suit la balise <scm> de votre pom.xml :
<scm> <url>https://github.com/arey/maven-config-github-cloudbees</url> <connection>scm:git:ssh://[email protected]/arey/maven-config-github-cloudbees.git</connection> <developerConnection>scm:git:ssh://[email protected]/arey/maven-config-github-cloudbees.git</developerConnection> </scm>
L’accès en écriture sur un repo GitHub requière l’utilisation du protocole SSH. L’URL est conforme à ce qui est spécifié dans la documentation de référence maven [3] :
scm:git:ssh://server_name[:port]/path_to_repository
A noter une syntaxe légèrement différent au chemin SSH affiché sur GitHub : /arey et non :arey, le caractère : étant utilisé pour préciser le port de connexion.
Pour tester la configuration maven, vous pouvez par exemple utiliser le plugin scm pour créer un tag. C’est ce plugin qui est utilisé par le plugin release.
mvn org.apache.maven.plugins:maven-scm-plugin:1.6:tag -Dtag=test -Dbasedir=.
Vous devriez obtenir les logs suivants :
[INFO] --- maven-scm-plugin:1.6:tag (default-cli) @ maven-config-github-cloudbees --- [INFO] Final Tag Name: 'test' [INFO] Executing: cmd.exe /X /C "git tag -F D:\tmp\maven-scm-1264232534.commit test" [INFO] Working directory: D:\dev\workspaces\WS_GitHub\maven-config-github-cloudbees [INFO] Executing: cmd.exe /X /C "git push ssh://[email protected]/arey/maven-config-github-cloudbees.git test" [INFO] Working directory: D:\dev\workspaces\WS_GitHub\maven-config-github-cloudbees
1 minute. 2 minutes. Le plugin s’arrête là, comme bloqué. L’occupation CPU est à 0%. Ne cherchez pas, vous êtes sous Windows.
En interne, le plugin scm exécute des lignes de commandes git.
Sous Windows, la ligne de commande git est exécutée par l’interpréteur de commandes cmd.exe en mode non interactif.
Or, lorsque vous essayez manuellement de pousser vos modifications vers GitHub depuis un bash git ou une ligne de commande avec git dans le path, Git vous demande systématiquement votre passphrase :
git push Enter passphrase for key '/c/Users/Antoine/.ssh/id_rsa':
L’explication est là : lors d’un tag ou d’un push, le plugin scm est bloqué car il attend votre passphrase. Pour autant, il ne vous demande jamais de le saisir. Vous vous retrouvez bloqué.
L’une des solutions permettant de résoudre ce problème est de répondre à la question : « Comment faire pour que Windows retienne ma passphrase ? » Stackoverflow.com vous donne la réponse [4].
En résumé, vous allez demander à git d’utiliser PuTTY pour communiquer en SSH avec GitHub. L’agent d’authentification SSH Pageant sera utilisé pour conserver votre clés privée Github en mémoire pour que vous puissiez vous authentifier sans avoir besoin de retaper votre phrase de passe à chaque fois. Voici le mode opératoire :

Pour tester la configuration, ouvrir une nouvelle fenêtre de commande et exécuter la commande suivante :
C:\Software\Dev\Putty>plink.exe [email protected] Using username "git". Server refused to allocate pty Hi arey! You've successfully authenticated, but GitHub does not provide shell access.
La création d’un tag par le plugin scm de maven doit désormais aboutir.
Avant de pouvoir effectuer une release, il est encore nécessaire de configurer les repository maven de votre forge CloudBees. Il s’agit ici de configuration maven relativement ordinaire.
Lors de la phase de déploiement d’un artefact, 2 repositories sont nécessaires, l’un pour déployer des releases,et l’autre pour déployer des snapshots :
<distributionManagement> <downloadUrl>https://github.com/arey/maven-config-github-cloudbee</downloadUrl> <repository> <id>javaetmoi-cloudbees-release</id> <name>javaetmoi-cloudbees-release</name> <url>dav:https://repository-javaetmoi.forge.cloudbees.com/release/</url> </repository> <snapshotRepository> <id>javaetmoi-cloudbees-snapshot</id> <name>javaetmoi-cloudbees-snapshot</name> <url>dav:https://repository-javaetmoi.forge.cloudbees.com/snapshot/</url> </snapshotRepository> </distributionManagement>
Point d’attention : les repositories CloudBees ne sont accessibles en écriture que par le prococole WebDAV. Les URL des repository doivent donc être préfixées par un dav:
L’extension maven wagon-webddav est requis pour que maven puisse interprêtrer le dav:. A ajouter dans la balise <build> de votre configuration :
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-webdav</artifactId>
<version>1.0-beta-2</version>
</extension>
</extensions>
Afin que maven puisse accéder à ces repository pour télécharger les snapshots et les releases, il est nécessaire de les déclarer, soit dans le pom.xml de votre projet, soit dans le fichier setting.xml global ou local à l’utilisateur (ce qui est une bien meilleure pratique) :
<repositories> <repository> <id>javaetmoi-cloudbees-release</id> <name>javaetmoi-cloudbees-release</name> <url>https://repository-javaetmoi.forge.cloudbees.com/release/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>javaetmoi-cloudbees-snapshot</id> <name>javaetmoi-cloudbees-snapshot</name> <url>https://repository-javaetmoi.forge.cloudbees.com/snapshot/</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>
Lors d’un déploiement distant (ex : mvn deploy), maven doit disposer des paramètres de connexion pour écrire dans l’un ou l’autre des repository. A configurer dans le fichier setting.xml global ou local de l’utilisateur :
<servers> <server> <id>javaetmoi-cloudbees-snapshot</id> <username>javaetmoi</username> <password>Mot de passe CloudBees</password> </server> <server> <id>javaetmoi-cloudbees-release</id> <username>javaetmoi</username> <password>Mot de passe CloudBees </password> </server>
Attention, bien que le mot de passe soit celui que vous utilisez pour vous connecter à vore compte CloudBees, le username ne correspond pas à votre adresse email, mais celui spécifié dans la forge CloudBees comme le montre la capture d’écran ci-contre.
Pour figer sa version, le plugin maven release peut également être déclaré dans votre pom.xml :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.2</version>
</plugin>
Ca y’est, toute la configuration est en place. A vous de jouer :
mvn release:prepare release:perform
Afin d’avoir sous la main un squelette pour un prochain projet, j’ai initié un projet GitHub regroupant toute la configuration maven nécessaire : https://github.com/arey/maven-config-github-cloudbees [9]. Vous pouvez y télécharger l’intégralité du pom.xml et du settings.xml décrits dans cet article]. Ce projet a fait des émules puisque le code a été forké par la CloudBees-Community [10] de Github.
Pour ne plus avoir besoin à configurer PuTTY, un axe d’amélioration du plugin release serait de pouvoir s’appuyer un provider Git en full java, basé par exemple sur JGit [11] (projet utilisé par le plugin Eclipse EGit). Initié par Olivier Lamy, le projet maven-scm-provider-jgit [12] semble malheureusement s’être arrêté avant que jgit ne bascule sous le giron de la fondation Eclipse. Avis aux contributeurs !!
Références :

Dans ce deuxième ticket, j’aimerais vous parler du projet Hibernate Hydrate [1] que j’ai récemment publié sur GitHub. Au cœur de ce projet : une seule classe Java proposant une unique fonctionnalité. En quelques années, c’est la seconde fois que j’ai eu besoin de coder ce genre de fonctionnalité. Aussi, je me suis dit qu’il serait pratique de l’avoir sous le coude pour une prochaine fois et, au passage, vous en faire profiter.
Origine des lazy exceptions
En quoi consistent ce projet et cette fameuse fonctionnalité ? Eh bien, sous certaines conditions, résoudre un problème récurrent lors de l’utilisation d’Hibernate. En effet, lorsque l’on tente d’accéder à un objet détaché de la session Hibernate, ce dernier n’est pas forcément entièrement chargé en mémoire : son proxy ou ses propriétés peuvent ne pas être initialisés, ce qui est par exemple le cas d’une relation déclarée comme paresseuse (ou lazy). Et c’est à cet instant-là, qu’Hibernate lève la tant redoutée LazyInitializationException.
Par objet détaché, j’entends un objet évincé de la session (retirée du cache de premier niveau par un session.clear() ou un evict()) ou dont la session est fermée (session.close())
Dans une application, ce phénomène est susceptible de se produire à plusieurs niveaux :
La documentation d’Hibernate propose plusieurs solutions pour remédier à ce problème. Plus encore, elle explique ce qu’il faut éviter de faire, comme par exemple ouvrir une autre unité de travail (transaction) pour charger les données manquantes.
Solutions préconisées
Pattern Open Session In View
Une première solution consiste à utiliser le pattern Open Session In View [2]. Dans une application web, ce pattern peut par exemple être implémenté à l’aide d’un filtre de servlets. L’arrivée d’une requête HTTP initie l’ouverture d’une transaction et de la session Hibernate correspondante. Une fois la vue rendue et prête être renvoyée au client, la session est fermée et la transaction est validée.
Le pattern Open Session In View ne peut pas s’appliquer dans une architecture technique 3 tiers où la couche présentation et la couche métier sont déployées physiquement sur 2 serveurs différents, et donc 2 JVMs. Ce pattern n’est également pas valable dans le cadre d’une application web riche utilisant Ajax et JavaScript pour récupérer puis parcourir le modèle métier.
Pré-chargement sur mesure
Personnellement, je recommande généralement à ce que les transactions soient gérées au niveau de la couche métier. En effet, à ce niveau, le service métier connait l’usage des objets qu’il va charger depuis la base de données. Il est capable d’utiliser le DAO ayant la stratégie de pré-chargement [3] (ou fetching) adaptée au traitement métier.
Pour rappel, le pré-chargement des relations peut être configuré de 2 manières :
Par défaut, dans Hibernate 3.x, les associations vers une autre entité ou une collection d’entités sont chargées tardivement ; c’est-à-dire à la demande, lorsque l’on essaie d’accéder à l’entité ou à la collection (et que la session est ouverte). Qui plus est, les stratégies définies statiquement ne sont pas forcément utilisées lors d’un requêtage HQL.
Une bonne pratique issue du guide de référence d’Hibernate [4] consiste à conserver le comportement par défaut d’Hibernate et à redéfinir la stratégie de pré-chargement à chaque usage. Cela permet d’optimiser votre code et de ramener les données dont vous avez strictement besoin.
Comme illustré dans l’article Hibernate Survival Guide [5], et grâce au cache de premier niveau d’Hibernate, il est parfois plus performant de découper sa requête en plusieurs requêtes, notamment lorsque la grappe d’objets est complexe et la cardinalité des associations importante.
Hybernate Hydrate à la rescousse
La solution que je vais vous présenter peut être utilisée conjointement avec la solution du pré-chargement sur mesure.
La méthode statique deepHydrate de la classe LazyLoadingUtil permet de charger dans sa globalité la grappe d’objets qui lui est passée en paramètre. Seule contrainte, cette méthode doit être appelée avant que la session Hibernate et la transaction associée ne soient clôturées.
Voici un exemple d’utilisation :
Employee employee = (Employee) session.get(Employee.class, 1); LazyLoadingUtil.deepHydrate(session, employee);
Techniquement, la méthode deepHydrate() utilise le méta-modèle Hibernate (interface ClassMetadata) pour parcourir l’ensemble du graphe des objets persistés et déterminer le type des propriétés et des relations du modèle. Ainsi, elle peut naviguer récursivement dans le graphe. Les proxy rencontrés sont initialisés puis résolus. Les collections persistantes sont initialisés puis itérés.
Dans le cas d’un graphe cyclique, un mécanisme de garde permet d’éviter toute boucle infinie.
La classe TestLazyLoadingUtil propose des exemples d’utilisation.
Une variante est disponible pour les applications utilisant JPA avec Hibernate pour provider : JpaLazyLoadingUtil.
Pour l’essayer, vous avez le choix entre un copier / coller, un git clone ou bien l’ajout d’une dépendance maven et du repo qui va avec :
<dependency>
<groupId>com.javaetmoi.core</groupId>
<artifactId>javaetmoi-hibernate4-hydrate</artifactId>
<version>2.0</version>
</dependency>
Les artefacts du projet Hybernate Hydrate sont disponibles sur Maven Central.
Conclusion
Pour terminer cette présentation, voici un tableau récapitulatif qui devrait vous permettre d’orienter votre choix sur l’usage ou non de cette petite librairie :
| Scénarios pour lesquels écarter cette solution | Scénarios favorables à son utilisation |
|
|
De mon côté, ce modeste travail de capitalisation m’a permis de renouer avec l’open-source ; en tant que contributeur j’entends. Mon dernier code poussé sur Source Forge datait en effet de l’an 2000 …
Cela m’aura également permis de me familiariser davantage avec GitHub : syntaxe MarkDown, pages wiki gérées par git ou bien encore les releases avec maven. Ce dernier point fera d’ailleurs l’objet d’un prochain article.
J’ai également pu adhérer au programme Free and OpenSource (FOSS) de CloudBees, ce qui vous permet d’accéder librement au Jenkins d’Hibernate Hydrate [6].
Enfin, si vous êtes un jour amené à utiliser ce code, je serais intéressé de le savoir. Et si vous voulez contribuer (ex : support d’autres ORM, annotation + post-processeur Spring …), les portes sont grandes ouvertes.
Références :