Mardi 14 décembre, alors qu’un froid polaire est tombé sur la capitale, c’est en compagnie d’Olivier Croisier que nous avons terminé la saison 2010 du Paris JUG. Une présentation de 2 heures sur les Annotations… à première vue on pense qu’il va tenir 10 minutes… mais pas du tout. Ce fut une présentation bien pointue, un moyen de dire qu’aux soirées du Paris JUG… on parle aussi Java.
Olivier Croisier est consultant et formateur chez Zenika. Avec 41 collaborateurs, Zenika est bien connu maintenant de la communauté parisienne. Il est l’auteur du blog « The Coder’s Breakfast » et de ses fameux Quiz. Olivier est aussi certifié Spring, certifié Java 5, formateur certifié Terracotta, et surtout le seul Français à ma connaissance qui soit certifié JavaSpecialist. Bref si vous le recevez en entretien et que vous lui posez des questions sur Java, je pense que vous allez vous faire balader.
@Introduction
Les Annotations en Java aujourd’hui sont de plus en plus présentes. Après une période XML, les frameworks modernes sont très friands des Annotations. Comprendre leur fonctionnement, expliquer les cas d’usages courants, puis ensuite les cas extrêmes, c’est le plan de la soirée. J’ai bien aimé lorsqu’Olivier dit : « les enfants sont couchés, maintenant on peut jouer avec les Annotations et faire de drôles de trucs… »
Avant l’introduction des Annotations dans le langage Java, vous pouviez utiliser les tags de la Javadoc. Qui se souvient de XDoclet ? Et de l’usage que nous en faisions durant la période « EJB 2.1 sauveur du monde » ? Aujourd’hui nous trouvons quelques annotations dans Java SE comme @Deprecated ou @SuppressWarnings, mais surtout beaucoup d’annotations dans Java EE. Bien entendu les frameworks comme Spring ou Hibernate, ou les spécifications comme JPA, nous montrent qu’aujourd’hui la méta-programmation est un point important de Java. D’où l’intérêt de comprendre comment fonctionne celles-ci et comment écrire ses propres annotations.
Il est possible d’annoter un peu tout ce que l’on veut, mais il n’est pas possible de déclarer plus d’une fois une même annotation sur un type donné (comme une classe par exemple). Pour annoter un package, il est nécessaire de déclarer un fichier package-info.java, qui contiendra la déclaration du package, ses annotations et sa javadoc. Si vous utilisez par exemple Apache CXF avec JAXB, la déclaration des schémas XML s’effectue dans une annotation de type package. Je n’ai pas le lien sous la main, mais vous trouverez cela sur Google. Les Annotations peuvent prendre des paramètres, qui peuvent aussi avoir des valeurs par défaut.
Ecrire sa propre annotation
A part parce que c’est fun, essayez d’écrire une annotation afin de comprendre le fonctionnement de celles-ci. Déclarée comme un type spécial d’interface, une annotation est compilée comme une interface héritant de java.lang.annotation.Annotation
public @interface MyAnnotation { }
Olivier présente ensuite en détail comment écrire son annotation, les différents Types d’annotation, les Targets, la Retention avec 3 valeurs possibles pour la RetentionPolicy. Vous pouvez déclarer des annotations n’ayant une durée de vie que dans le code source de votre classe, dans le .class (valeur par défaut) ou enfin au niveau Runtime, donc disponible lors de l’execution du code.
La méta-annotation @Inherited sur une classe permet aussi d’indiquer qu’une annotation sera héritée par les classes filles de la classe annotée.
Je vous renvoie aux slides de la présentation d’Olivier qui sont assez détaillés. Je ne couvrirai pas ici les détails sur comment écrire son annotation.
Outillages sur les annotations
Olivier continue la montée en puissance. Nous attaquons maintenant l’annotation processor. Entre la version 5 et la version 6 de Java, il y a eu quelques changements. Java 5 a introduit APT, un outil en ligne de commande qui permet d’effectuer du processing d’annotation sur un ensemble de classe. Java 6 introduit ce que l’on appelle « Pluggable Annotation Processor ». Intégré au processus de compilation, le paramètre -processor ou le Service Provider Interface, dont Olivier a expliqué le fonctionnement dans l’un de ses articles.
Alors à quoi peut bien servir un annotation processor vous vous dîtes ? Et bien à effectuer des traitements complémentaires sur votre code, à générer du code, à extraire de la documentation, à valider votre code, à vérifier des règles de nommage, bref c’est surtout une approche qui intéresse ceux qui écrivent des APIs. Mais Olivier souligne qu’il est possible à peu de frais d’en ajouter dans son projet, afin par exemple de renforcer des règles d’architectures lors de la compilation.
Un petit mot sur Lombok. Olivier explique que Lombok améliore magiquement vos classes en évitant de devoir écrire une certaine quantité de code. Il suffit par exemple de placer une annotation @Data sur une classe simple pour que vos getters/setters/toString/equals/hashCode soient générés par Lombok.
Le souci, c’est que Lombok viole la règle de non-modification du code source par rapport au byte-code. Cela créé une liaison forte sur la façon dont Lombok s’en sort avec votre version de Java. Et cela n’est pas fait avec un Annotation Processor si j’ai bien compris l’explication d’Olivier. Si votre compilateur cible ne supporte pas Lombok, votre projet ne pourra plus compiler. Et comme dit Olivier, va expliquer à ton chef que ton projet ne compile plus parce que tu es passé de Java 1.6.0.18 à 1.6.0.22… Attention donc. Si quelqu’un peut compléter, je ne suis pas certain d’avoir toutes les informations.
Olivier fait ensuite plusieurs démonstrations sur les AnnotationProcessors. C’est beau et c’est violent. Et en même temps j’ai trouvé que ses exemples étaient bien calibrés. On est plus dans le helloWorld, les enfants sont couchés et on peut sortir du gros code un peu sale, qui injecte des annotations sur des classes (ce sont les mots d’Olivier qui fait rire la salle).
Après plusieurs passages avec IDEA IntelliJ, car oui Olivier est passé d’Eclipse à IDEA IntelliJ, on a à peine le temps de souffler, qu’il repart de plus belle.
Cela donne des moments comme celui-ci :
@SupportedAnnotationTypes("com.zenika.*") public class MyProcessor extends AbstractProcessor { Types types; Elements elements; Messager messager; Filer filer; public void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); types = processingEnv.getTypeUtils(); elements = processingEnv.getElementUtils(); messager = processingEnv.getMessager(); filer = processingEnv.getFiler(); } public boolean process( Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { // TODO } }
A peine le temps de marquer le code, je ramasse mes derniers neurones, je loupe 2 slides, ça va vite. C’est bien. Vite, vite, il faut essayer de comprendre, c’est simple mais c’est puissant….
public static void injectClass (Class<?> targetClass, Annotation annotation) { // Initialisation des maps d'annotations targetClass.getAnnotations(); // Récupération de la map interne des annotations Field mapRef = Class.class.getDeclaredField("annotations"); mapRef.setAccessible(true); // Modification de la map des annotations Map<Class, Annotation> annots = (Map<Class, Annotation>) mapRef.get(targetClass); if (annots==null || annots.isEmpty()) { annots = new HashMap<Class, Annotation>(); } pojoAnnotations.put(annotation.annotationType(), annotation); mapRef.set(targetClass, pojoAnnotations); }
Le code ci-dessus permet d’injecter une annotation par réflexion. Suivez le guide, tenez vous la main, les femmes et les enfants d’abord…
Bref pour la fin, c’était vraiment intéressant et pointu. Cela donne envie d’aller suivre la formation Java Avancé qu’Olivier donne aussi.
Conclusion
Les annotations sont utilisées de plus en plus dans les différents socles applicatifs Javas. Que ce soit Spring, JPA, JEE6 ou autre, vous êtes certain de croiser des annotations. La programmation par méta-donnée permet d’ajouter des fonctions à du code dans une approche complémentaire du code Java classique. Tout est partie de javadoc, puis de l’usage détourné que nous en avons fait pendant un temps avec XDoclet, puis des annotations, qui aujourd’hui permettent de configurer et surtout générer un bon nombre de ressources, comme en Java EE et avec Spring.
Retrouvez les slides sur le blog d’Olivier, merci pour la soirée.
Post-scriptum
Rendez-vous le lundi 28 février 2011 à Paris pour venir fêter le 3ème anniversaire du Paris JUG avec toute l’équipe. Le thème cette année : « Sifflez en travaillant« . Nous avons lancé un appel, si vous souhaitez venir présenter un sujet, vous pouvez proposer votre présentation via le site du Paris JUG. Rendez-vous sur la page dédiée pour savoir comment proposer votre sujet, avant le 7 février.
0 no like
Pas tout à fait d’accord sur la partie Lombok.
D’abord il y a l’outil qui te permet de transformer tes annotations en code si ton environnement ne supporte pas l’annotation processor. Donc non, tu n’es pas maqué avec Lombok.
Ensuite je ne suis pas d’accord avec Olivier Croisier qui dit que ton ide est capable de générer ce que fait Lombok. Il sait effectivement le faire mais à ma connaissance, il ne sait pas maintenir un toString(), un hashcode(), un equals() quand tu ajoutes des attributs à ta classe.