Paris JUG: Soirée sur la Performance des applications Java
Thursday, March 20th, 2008Le Paris Java User Group vient d’annoncer sa prochaine soirée, consacrée aux performances des applications Java.
(more…)
Le Paris Java User Group vient d’annoncer sa prochaine soirée, consacrée aux performances des applications Java.
(more…)
Lorsque j’ai entendu parler la première fois de l’initiative Paris Java User Group il y a quelques semaines, je me suis demandé quel était son intérêt. Après tout, il y a déjà eu dans le passé le Club Java, créé en 1997, qui a fini par mourir petit à petit (le site existe toujours mais n’a pas été mis à jour depuis 2005).
Une autre initiative, l’OSSGTP (Open Source Software Get Together Paris) a regroupé de nombreuses personnes actives dans le monde open source, en particulier Java. On peut avoir l’impression que cette association a atteint ses objectifs, maintenant que des sociétés telles que XWiki ou G2One ont vu le jour. D’où une nette baisse de son activité, en particulier depuis Javaday 2006 où l’OSSGTP avait brillé par la présence de plusieurs de ses membres dans plusieurs débats.
La disparition de ces deux organisations ne trahissent-elles pas une certaine désaffection de la communauté Java? Peut-être que ses membres ont pris de l’âge et préfèrent limiter leurs activités extra-travail? developpez.com ne répond-il pas aux besoins du reste d’entre nous?
C’est donc avec un certain scepticisme que je me suis rendu mardi 12 février à la réunion d’inauguration du Paris JUG, animée par Antonio Goncalves & David Dewalle. Contrairement à mes attentes, il semble que cette initiative va réellement déboucher sur quelque chose.
(more…)
J’ai eu envie hier soir de tester ce langage dont des échos résonnent très positivement depuis presque un an maintenant. Et grâce à un tutoriel exceptionnellement bien fait sur le site officiel de Groovy, j’ai pu rapidement évaluer la chose. Première impression : c’est rapide et fun de taper trois mots et de voir tout ce qu’on peut faire avec. Ca m’a immédiatement rappellé mes ébats avec la console d’Ocaml au temps béni où on est un jeune fou qui délaisse les maths pour l’info.
Je resitue juste le contexte de Groovy. Le constat est que Java a su faire la synthèse du meilleur de ce qui existait à l’époque en termes de développement objet. Or, aujourd’hui, de nombreux développeurs sont adeptes de langages dynamiques (scripting) aux syntaxes plus flexibles. C’est donc dans cette volonté que Groovy est né profitant de l’expérience acquise par la pratique de Java, Perl ou autres Python.
On découvre donc des concepts comme la closure qui considère le code comme des données. Cela m’a fait tout de suite penser au javascript “moderne” (post framworks du web 2.0 comme Ext Js voir mon précédent post) qui embrace cette approche. On peut donc réaliser une affectation d’une suite d’instruction (“closure”) à une variable afin de la passer en entrée à une fonction :
square = { it * it }
square(9)
résultat : 81
[ 1, 2, 3, 4 ].collect(square)
résultat : [ 1, 4, 9, 16 ]
Comme vous pouvez le constater, la syntaxe s’en trouve grandement allégée par rapport au code java équivalent.
Avec l’arrivée des EJB3, Sun a mis en place une nouvelle API, « Java Persistence API » également connue sous le sigle JPA. JPA est une spécification qui définit un framework de persistance, introduite dans la JSR-220 (nom officiel de la spécification EJB3.0).Les frameworks de persistance, également connus sous le nom d’ORM (Object Relationnal Mapping), ont pour objectif de fournir un mapping objet/relationnel entre les SGBDR et les applications Java. Les plus répandus sur le marché sont Hibernate ou encore TopLink. JPA a tenu compte de l’ensemble de ces frameworks pour standardiser l’univers de la persistance en Java.
Génération de proxy coté serveur : un classique
La génération dynamique de proxy en Java est un mécanisme relativement nouveau, même si la notion même de proxy est standardisée depuis Java 1.4. L’émergence de CGLIB tout d’abord, puis de Javassist, a permet le développement de nombreuses librairies manipulant de simples POJO (donc sans héritage technique). En fait, l’astuce consiste pour ces librairies a modifier votre POJO, par héritage, en lui ajoutant dynamiquement les propriétés nécessaires au bon fonctionnement de la librairie:

C’est bien entendu le mécanisme utilisé par Hibernate par exemple pour instrumentaliser vos POJO et y ajouter les infos dont il a besoin.
Tentative d’évasion
Si astucieux soit-il, ce mécanisme est source de graves ennuis dès qu’il s’agit de quitter la JVM sur laquelle a été généré le proxy. Essayer par exemple d’envoyer un objet Hibernate par JMS : si le lecteur ne possède pas l’archive Hibernate dans son classpath, c’est l’erreur de désérialisation assurée…
Le problème se pose donc pour GWT, que l’on peut assimiler _ entre autre _ à une JVM Javascript. Imaginons une classe ‘Message’ que nous souhaitons instrumenter afin d’y ajouter des informations de débug, de sécurité, etc…
Pour cela, il faut étendre la classe Message en MessageProxy, grâce à Javassist par exemple :
ClassPool pool = ClassPool.getDefault();
CtClass proxyClass = pool.makeClass("MessageProxy");
proxyClass.setSuperclass(pool.get("Message"));
...
return proxyClass.toClass(getClassLoader());
Tant que la classe reste coté serveur, pas de souci. Par contre, toute tentative d’envoyer cette classe sur la lune… euh, coté client
se heurtera à une erreur de sérialisation :
com.google.gwt.user.client.rpc.SerializationException: Type ‘<Proxy>’ was not included in the set of types which can be serialized by this SerializationPolicy. For security purposes, this
type will not be serialized.
Serialization Policy : vos papiers…
En effet, en GWT 1.4, la politique de sérialisation a changé. Afin d’éviter un héritage technique hideux avec IsSerializable, l’option a été prise de lister à la compilation les classes sérialisables (contenues dans les fichiers gwt.rpc générés). D’où un conflit évident avec la génération dynamique de proxy…
De plus, le processus de sérialisation GWT est foncièrement statique. Même si la politique de sérialisation n’empêchait pas l’envoi de proxy, les données supplémentaires du Proxy ne seraient tout simplement pas envoyées sur le client, car la classe Javascript ne contient pas les champs correspondant à ces données.

Il faut donc générer une classe Javascript qui soit le pendant de notre proxy. Pour cela, GWT a une solution : les Generator. Ce mécanisme, relativement peu documenté, s’appuie sur le principe de deferred binding utilisé notamment par l’internationalisation de la librairie.
Pour faire court, la mise en place de generators nécessite 3 éléments :
...
ClassSourceFileComposerFactory composerFactory =
new ClassSourceFileComposerFactory("", "MessageProxy");
composerFactory.setSuperclass("Message");
SourceWriter sourceWriter =
composerFactory.createSourceWriter(context, printWriter)
...
sourceWriter.commit(logger);
<generate-with class="net.sf.hibernate4gwt.rebind.GwtProxyGenerator">
<when-type-assignable class="net.sf.hibernate4gwt.proxy.IProxy" />
</generate-with>

Pour plus de détails sur la mise en place de générateurs, je vous renvoie directement au billet correspondant de l’excellent blog Timepedia ou au non moins l’excellent « GWT in action » qui traitent du sujet en profondeur.
Generator coté serveur : une mauvaise idée
J’avoue avoir essayé de récupérer le proxy généré par GWT dans mon code Java. Après tout, en hosted-mode, ma classe est bien instanciée en Java, non ?
En fait, les Generator GWT sont une technologie clairement orienté couche cliente. Un appel à GWT.create coté serveur soulève une automatiquement une exception, et hacker le hosted-mode pour récupérer la classe Java impliquerait que l’application embarque le moteur Tomcat embarqué utilisé dans ce mode. Quand je vous disais que c’était une mauvaise idée ![]()
Faisons le point…
Donc pour envoyer un proxy serveur coté client en GWT, il faut donc :
Bien entendu, il est fortement conseillé de factoriser la génération de proxy dans une même classe, la cohérence du proxy coté serveur et client étant cruciale pour le passage d’une JVM (classique) à l’autre (Javascript).
Quelques détails d’implémentation
Sur le papier, les étapes ci-dessus devraient suffire à faire créer des proxy dynamiques. En pratique, il reste un dernier petit détail à régler…
Vous vous souvenez de la SerializationPolicy dont j’ai parlé il y a quelques lignes ? Depuis la version 1.4, le compilateur génère une liste de classes autorisées à être envoyées par RPC (et donc sérialisées en Javascript), stockés dans un fichier ‘gwt.rpc’.
Première constatation : les proxys créés par notre Generator y apparaissent explicitement s’ils font partie de la signature des méthodes de notre RemoteService, ce qui est assez surprenant pour une technologie orientée cliente !
Deuxième constatation, plus désagréable celle-ci : l’implémentation de SerialializationPolicy génère sa « white-list » au premier appel. Pour cela, elle tente d’instancier toutes les classes contenues dans ses fichiers ‘gwt.rpc’ associé. Il faut donc créer les proxy avant cette vérification, sous peine de faire systématiquement échouer l’appel à cause d’une ClassNotFoundException sur celui-ci…
Là aussi, il existe plusieurs solutions :
public Class loadClass(String name) throws ClassNotFoundException
{
if (isProxy(name))
{
// Get source class name
//
String sourceClassName = getSourceClassName(name);
Class sourceClass = _wrappedClassLoader.loadClass(sourceClassName);
// Generate proxy
//
return generateProxyClass(sourceClass);
}
else
{
// Load class
//
return _wrappedClassLoader.loadClass(name);
}
}
Et ça marche…
J’ai fait plusieurs tests (en fait, j’utilise cette technique pour remplacer un héritage technique d’hibernate4gwt par une simple interface de marquage) et cela semble fonctionner dans le cas qui m’intéresse.
Par contre, il existe quelques points à améliorer avant de rendre un tel mécanisme réellement transparent, à cause notamment des appels explicites à GWT.create (je n’ai pas encore réussi à berner le compilateur GWT
) et de l’enrobage nécessaire du ClassLoader.
Avis aux amateurs !
Cet été la commission de définition de JPA 2.0, estampillée JSR 317, a été créée.
Au menu, pas mal de choses intéressantes (traduction approximative
):
Ces quelques points ne sont que des propositions : la liste n’est ni close ni exhaustive.
Les plus perspicaces d’entre vous noteront que nombre de ces “nouvelles” fonctionnalités, tel l’API Criteria ou le détachement, reprennent des mécanismes déjà existants dans Hibernate.
Il semble donc que RedHat soit décidé à continuer la standardisation de sa librairie.
Autre point intéressant : le calendrier.
Autant dire qu’il ne faut pas attendre JPA 2 pour demain. De plus, il est clairement stipulé que le planning de cette JSR est calé sur celle de la définition de J2EE 6 (JSR 316), menée en parallèle.
J’aurais voulu comparer cette roadmap JPA2 avec celle d’Hibernate, mais la page dédiée semble obsolète. Dommage…
Dans ce post, j’applique la sugession Chad Fowler dans son livre “My Job Went to India: All I Got Was This Lousy Book” : pour être sûr qu’on a bien compris quelquechose, il faut essayer de l’expliquer.
Voyons ce qu’est JAXB. Ma problématique est d’écrire le contenu d’une table relationnelle en XML. La structure de la table est déjà créée et le format XML déjà connu. Le but est de trouver le moyen le plus adapté dans le langage java.
Après avoir refoulé immédiatement l’idée d’écrire la sauce XML dans un fichier, je me suis intéressé à JAXB.
%JDK_HOME%/bin/xjc schema.xsd
Elle permet de générer une implémentation java d’objets qui se conforment au schéma. On dispose donc d’une hiérarchie d’objets de style javabean qui peuvent recevoir autant de données qu’un fichier XML implémentant le schéma XML.
Avantages:
Inconvénients:
Conclusion: positive pour mon usage.
Evolution: intégrer la génération de code dans la procédure ant pour détecter les changements du schéma ?
Pour en savoir plus, je vous propose consulter cette présentation : JAXB.ppt
Avant-propos (ou le pourquoi du comment)
La sérialisation GWT répond à une règle stricte : seules quelques classes issues de la Java Runtime Environment sont supportées, et malheur à quiconque s’en écarte. De manière cohérente, certaines classes de base sont supportées. Par contre, rien n’assure que les classes dérivées le soient.
C’est justement ce comportement, au demeurant fort logique, qui est la cause de nombreuses SerializationException lors de l’envoi de date du serveur vers le client.
En effet, il est fort probable que le moteur de persistance, peu au fait des subtilités de sérialisation Javascript, aie tôt fait de remplacer votre instance de java.util.Date par une dérivation SQL (java.sql.Date ou java.sql.Timestamp) plus proche de son modèle relationnel.
Généralement, le contournement préconisé revient à créer un objet Date standard à partir de sa variation SQL afin de ne pas heurter môssieur GWT
. Sauf que… la classe Timestamp est plus précise que la classe Date, et donc que cette conversion peut poser quelques problèmes de synchronisation au retour sur le serveur. Je pense notamment aux malheureux qui ont basé la gestion de version sur un champ Timestamp et qui se retrouvent bien embêtés avec leur valeur de retour tronquée…
Ce problème ayant été relevé par un utilisateur de ma librairie hibernate4gwt, j’ai décidé de m’attaquer au problème.
Portage du timestamp : premier essai
Dans ma grande naïveté (je suis parfois d’un optimisme béat), j’ai cru qu’en définissant une classe d’émulation classique _ comprenez implémentant (Is)Serializable _ le tour serait joué.
Hélas, trois fois hélas, la sérialisation JavaScript semble assez mal s’accommoder de l’héritage nécessaire entre Timestamp et Date. J’ai d’ailleurs ouvert une fiche de bug (n°1164) concernant ce problème… sans réponse à ce jour ![]()
Portage du timestamp : seconde tentative
Etant d’un naturel têtu, j’ai parcouru les sources de GWT à la recherche du mécanisme permettant la sérialisation de l’objet java.util.Date.
En fait, un objet émulé nécessite deux classes :
L’écriture de la classe d’émulation JSNI s’est avéré relativement simple, en m’appuyant sur l’existant Date, seul le champ « nanoseconds » devant être ajouté.
Le sérialiseur quand à lui répond à un certain nombre de règles plus ou moins tacites (il n’existe pas d’interface à implémenter) :
public final class Timestamp_CustomFieldSerializer
{
public static void deserialize(SerializationStreamReader streamReader,
Timestamp instance)
throws SerializationException
{
// no fields
}
public static Timestamp instantiate(SerializationStreamReader streamReader)
throws SerializationException
{
Timestamp instance = new Timestamp(streamReader.readLong());
instance.setNanos(streamReader.readInt());
return instance;
}
public static void serialize(SerializationStreamWriter streamWriter,
Timestamp instance)
throws SerializationException
{
streamWriter.writeLong(instance.getTime());
streamWriter.writeInt(instance.getNanos());
}
}
Notez bien que les méthodes utilisent et renvoie des objets de type Timestamp et non de simples objets, ce qui explique qu’il n’y ait pas d’interface générique à implémenter.
Et ça marche !
Dernière remarque : concernant le portage en Javascript d’une classe existante, c’est cette dernière qui est utilisée en Hosted Mode, et qu’il faut déployer l’application GWT en mode Web pour voir s’exécuter le code JSNI et valider son fonctionnement.
Article paru dans la newsletter #20 – Ete 2007
Plus qu’une évolution
La concurrence entre les frameworks J2EE est grande et seule l’adoption par un plus grand nombre assure la pérennité de ces derniers. Struts 2 arrive avec l’ambition de remplacer Struts 1 qui est aujourd’hui le framework de référence pour la majorité des développements.
Pour un nouveau développement, vous préconiseriez plutôt d’utiliser Hibernate ou JPA ?
De prime abord, la question peut sembler étrange tant Hibernate semble avoir inspiré le standard Java Persistence API. Les technologies sont même tellement proches qu’un tel choix s’avère presque paradoxal : après tout, Hibernate est une implémentation de JPA, cela revient donc à comparer un Coca et un Coca light ![]()
De prime abord, JPA semble le choix évident. C’est en effet une API standard, et donc interchangeable. Tout développement JPA fonctionne donc sans peine tant sur Hibernate que TopLink, OpenJPA, …
C’est tout ? Eh bien, oui, c’est tout ce que JPA apporte au monde Java.
Voyons maintenant ce qu’il enlève à un développement Hibernate.
En effet, JPA étant le plus petit dénominateur commun entre différentes librairies de persistance (Hibernate, TopLink, …), certaines fonctionnalités Hibernate ne font pas partie du standard et ne sont pas supportées par les autres implémentations (ou alors de manière tout aussi propriétaire).
On peut citer pêle-mêle (liste non exhaustive) :
Certains seront tentés de coder les fonctionnalités « standard » avec l’API JPA, et de revenir à l’API Hibernate lorsque le besoin s’en fait sentir. Comportement assez étrange et hypocrite en fait, puis que le code s’en trouve tout de même lié à Hibernate ! Quitte à choisir une API, autant être cohérent sur toute l’application…
Autre point à prendre en compte : l’évolution. Le processus de strandardisation est généralement un travail de longue haleine, qui se chiffre généralement en mois et en années. Du coup, l’intégration des fonctionnalités Hibernate absente de JPA (ou de nouvelles) ne se fera sans doute pas avant la prochaine version, la JSR 313 (J2EE 6), prévue… fin 2008 !
En passant, il est intéressant que noter que la capacité d’innovation de Sun frise le zéro absolu : les dernières « révolutions » Java (JUnit, Struts, Hibernate, GWT,…) proviennent toutes du monde du logiciel Open-Source
!
Et en attendant la JSR 313, que va faire Hibernate d’après vous ? Innover bien sûr !
A ce titre, la lecture de la FAQ Hibernate est assez éclairante :
Now that EJB 3.0 is out, is Hibernate dead?
Certainly not! We got involved in EJB 3.0 because we wanted to bring ORM technology to the masses. The EntityManager API defined by JSR-220 is just an alternative way to call Hibernate, from our point of view. We hope and expect that the standardization of ORM as a central, integrated piece of the J2EE platform will drive the next wave of adoption of ORM and Hibernate.
Because the standards process is an inappropriate place to innovate new functionality, and because it takes several years to validate a new idea and then work it into a final specification document, we will continue to develop and innovate our own APIs and use them to provide cutting edge features to those users for whom portability is not a major priority. For example, we are providing the cool new filtering functionality via the traditional Hibernate Session interface. In time, new features that prove sufficiently important will probably find their way into the EJB spec.
Clairement, Hibernate va continuer à évoluer (on pense notamment à Hibernate Shards ou Validator qui viennent d’être publiés récemment), et ces modifications ne seront intégrées à JPA que plusieurs mois ou plusieurs années plus tard.
Au vu de tels arguments, la question « Hibernate ou JPA » est sans doute plus difficile à trancher que de prime abord. L’interrogation centrale réside sans doute dans la cible du logiciel à développer : nécessite-t’il vraiment de fonctionner sur plusieurs implémentations de serveur d’application ? Vos développeurs peuvent-ils se passer des fonctionnalités propriétaires Hibernate telles que les Criteria, le réattachement, ou le filtrage dynamique ?
Des réponses à ces questions dépendront sans doute la préconisation adéquate…