Your SlideShare is downloading. ×
0
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Annotations Java par Olivier Croisier

869

Published on

Introduites avec Java 5, les annotations ont ouvert la voie à la méta-programmation et sont aujourd’hui présentes dans tous les frameworks et API Java. …

Introduites avec Java 5, les annotations ont ouvert la voie à la méta-programmation et sont aujourd’hui présentes dans tous les frameworks et API Java.

Au cours de la conférence, Olivier Croisier reviendra tout d’abord sur le principe des annotations et leur mise en œuvre au quotidien, puis démontrera l’étendue des possibilités qu’elles offrent à la compilation et au runtime, via les Annotation Processors et la Réflexion.

Olivier Croisier est expert Java chez Zenika. Il est certifié Java 5.0 avec 100%, Spring 2.5 avec 86% et est formateur certifié Terracotta. Olivier a notamment obtenu le titre de Certified JavaSpecialist Master Course Instructor de la part d’Heinz Kabutz, devenant ainsi le formateur JavaSpecialist de référence en France. Il est également l’auteur du blog The Coder’s Breakfast.

Published in: Technology
1 Comment
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total Views
869
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
21
Comments
1
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Les Annotations Java Enfin  expliquées  simplement !©Zenika 1
  • 2. Olivier Croisier Jaime  • Consultant Zenika tellement ses  quizz Java ! • Certifié Java 5.0 (100%) • Certifié Spring Framework • Formateur certifié JavaSpecialist (javaspecialists.eu) • Formateur certifié Terracotta • Blog : The Coders Breakfast ( thecodersbreakfast.net ) • Twitter : @OlivierCroisier (Effet dramatisé en post-production)©Zenika 2
  • 3. Plan • Présentation • Annotations, mode demploi • Annotations personnalisées • Outillage compile-time • Outillage runtime • Injection dannotations • Conclusion©Zenika 3
  • 4. Plan • Présentation • Historique • Où trouver des annotations ? • Annotations, mode demploi • Annotations personnalisées • Outillage compile-time • Outillage runtime • Injection dannotations • Conclusion©Zenika 4
  • 5. Présentation Historique • Java a toujours proposé une forme ou une autre de méta- programmation • Dès lorigine, loutil "javadoc" permettait dexploiter automatiquement des méta-données à but documentaire /** /** ** Méthode inutile Méthode inutile ** @param param Un paramètre (non utilisé) @param param Un paramètre (non utilisé) ** @return Une valeur fixe :: "foo" @return Une valeur fixe "foo" ** @throws Exception Narrive jamais (promis!) @throws Exception Narrive jamais (promis!) */*/ public String foo(String param) throws Exception {{ public String foo(String param) throws Exception return "foo"; return "foo"; }}©Zenika 5
  • 6. Présentation Historique • Ce système était flexible et a rapidement été utilisé / détourné pour générer dautres artefacts : fichiers de configuration, classes annexes... • Voir le projet XDoclet (xdoclet.sourceforfge.net) /** /** ** @ejb.bean @ejb.bean ** name="bank/Account" name="bank/Account" ** type="CMP" type="CMP" ** jndi-name="ejb/bank/Account" jndi-name="ejb/bank/Account" ** local-jndi-name="ejb/bank/LocalAccount" local-jndi-name="ejb/bank/LocalAccount" ** primkey-field="id" primkey-field="id" ** @ejb.transaction @ejb.transaction ** type="Required" type="Required" ** @ejb.interface @ejb.interface ** remote-class="test.interfaces.Account" remote-class="test.interfaces.Account" */ */©Zenika 6
  • 7. Présentation Historique • Reconnaissant le besoin dun système de méta-programmation plus robuste et plus flexible, Java 5.0 introduit les Annotations • Elles remplacent avantageusement les doclets dans tous les domaines – sauf bien sûr pour la génération de la Javadoc ! public class PojoAnnotation extends Superclass {{ public class PojoAnnotation extends Superclass @Override @Override public void overridenMethod() {{ public void overridenMethod() super.overridenMethod(); super.overridenMethod(); }} @Deprecated @Deprecated public void oldMethod(){ public void oldMethod(){ }} }}©Zenika 7
  • 8. Présentation Où trouver des annotations ? • Java SE propose assez peu dannotations en standard • @Deprecated, @Override, @SuppressWarnings • 4 méta-annotations dans java.lang.annotation • Celles définies par JAXB et Commons Annotations @ @ • Java EE en fournit une quantité impressionnante • Pour les EJB 3, les Servlets 3, CDI, JSF 2, JPA... @ • Les frameworks modernes en tirent également parti • Spring, Hibernate, CXF, Stripes... • Développez les vôtres !©Zenika 8
  • 9. Plan • Présentation • Annotations, mode demploi • Elements annotables • Annoter une classe, une méthode ou un champ • Annoter un package • Paramètres dannotations • Restrictions et astuces • Annotations personnalisées • Outillage compile-time • Outillage runtime • Injection dannotations • Conclusion©Zenika 9
  • 10. Annotations, mode demploi Elements annotables • Les annotations peuvent être apposées sur les éléments suivants : • Les classes, interfaces et enums • Les propriétés de classes • Les constructeurs et méthodes • Les paramètres des constructeurs et méthodes • Les variables locales • … et dautres éléments encore grâce à la JSR 308 (Java 7 8) • Mais aussi sur... • Les packages • Les annotations elles-mêmes (méta-annotations) !©Zenika 10
  • 11. Annotations, mode demploi Annoter une classe, méthode ou champ @Deprecated @Deprecated public class Pojo {{ public class Pojo @Deprecated @Deprecated private int foo; private int foo; @Deprecated @Deprecated public Pojo() {{ public Pojo() @Deprecated @Deprecated int localVar ==0; int localVar 0; }} @Deprecated @Deprecated public int getFoo() {{ public intfoo; return getFoo() return foo; }} public void setFoo(@Deprecated int foo) {{ public void setFoo(@Deprecated int foo) this.foo ==foo; this.foo foo; }} }}©Zenika 11
  • 12. Annotations, mode demploi Annoter un package • Comment annoter un package ? • La déclaration dun package est présente dans toutes les classes appartenant à ce package. Impossible dy placer une annotation : risque de conflit ou dinformation incomplète ! @Foo @Foo package com.zenika.presentation.annotations; package com.zenika.presentation.annotations; public class ClassA {} public class ClassA {} @Bar @Bar package com.zenika.presentation.annotations; package com.zenika.presentation.annotations; public class ClassB {} public class ClassB {}©Zenika 12
  • 13. Annotations, mode demploi Annoter un package • Solution : pour annoter un package, il faut créer un fichier spécial nommé package-info.java • Il contient uniquement la déclaration du package, accompagné de sa javadoc et de ses annotations /** /** ** Ce package contient le code source de Ce package contient le code source de ** la présentation sur les annotations. la présentation sur les annotations. */ */ @Foo @Foo @Bar @Bar package com.zenika.presentation.annotations; package com.zenika.presentation.annotations;©Zenika 13
  • 14. Annotations, mode demploi Paramètres dannotations • Les annotations peuvent prendre des paramètres • Ils peuvent être obligatoires ou facultatifs (ils prennent alors la valeur par défaut spécifiée par le développeur de lannotation) • Les paramètres se précisent entre parenthèses, à la suite de lannotation ; leur ordre nest pas important @MyAnnotation( param1=value1, param2=value2... )) @MyAnnotation( param1=value1, param2=value2... • Si lannotation ne prend quun paramètre, il est souvent possible dutiliser une notation raccourcie @MyAnnotation( value )) @MyAnnotation( value©Zenika 14
  • 15. Annotations, mode demploi Paramètres dannotations @WebInitParam( name="foo", value="bar" )) @WebInitParam( name="foo", value="bar"©Zenika 15
  • 16. Annotations, mode demploi Restrictions et astuces • Il est interdit dannoter plusieurs fois un élément avec la même annotation. Pour contourner le problème, on peut recourir à des annotations "wrapper" @SecondaryTables({ @SecondaryTables({ @SecondaryTable(name="city"), @SecondaryTable(name="city"), @SecondaryTable(name="country") @SecondaryTable(name="country") }) }) public class Address public class Address {...} {...} • Il est possible de séparer l@ du nom de lannotation ! @@ /** Javadoc */ /** Javadoc */ Deprecated Deprecated©Zenika 16
  • 17. Annotations, mode demploi Restrictions et astuces • Pour les paramètres : • Les valeurs des paramètres doivent être des "compile-time constants"... @MyAnnotation(answer == (true!=false) ?? 42 :: 0) @MyAnnotation(answer (true!=false) 42 0) • … mais ne peuvent pas être null (Et personne ne sait pourquoi !) @MyAnnotation(param == null) @MyAnnotation(param null)©Zenika 17
  • 18. Annotations, mode demploi Démos Démos • Mode demploi©Zenika 18
  • 19. Plan • Présentation • Annotations, mode demploi • Annotations personnalisées • Use-cases • Méta-annotations • Paramètres dannotations • Outillage compile-time • Outillage runtime • Injection dannotations • Conclusion©Zenika 19
  • 20. Annotations personnalisées A quoi ça sert ? • Pourquoi développer des annotations personnalisées ? • Pour remplacer / compléter des fichiers de configuration XML • Pour simplifier ou générifier une portion de code en recourant à la méta-programmation • Pour appliquer des règles de compilation supplémentaires, grâce aux Annotation Processors • … parce que cest fun !©Zenika 20
  • 21. Annotations personnalisées Syntaxe • Une annotation se déclare comme un type spécial dinterface • Elle sera compilée sous la forme dune interface héritant de java.lang.annotation.Annotation public @interface MyAnnotation {{ public @interface MyAnnotation }} • Il est ensuite possible de compléter lannotation avec : • Des paramètres •Pour véhiculer des données supplémentaires • Des méta-annotations •Pour spécifier les conditions dutilisation de lannotation©Zenika 21
  • 22. Annotation personnalisées Paramètres dannotations • Chaque paramètre se déclare sous la forme dune méthode (non générique, sans paramètres et sans exceptions) • Il peut posséder une valeur par défaut (compile-time constant), déclarée grâce au mot-clé "default" ; il est alors optionnel. public @interface MyAnnotation {{ public @interface MyAnnotation String message(); String message(); int answer() default 42; int answer() default 42; }} @MyAnnotation( message="Hello World" )) @MyAnnotation( message="Hello World" @MyAnnotation( message="Hello World", answer == 00 )) @MyAnnotation( message="Hello World", answer©Zenika 22
  • 23. Annotation personnalisées Paramètres dannotations • Si lannotation ne possède quun seul paramètre nommé "value", il est possible dutiliser une syntaxe raccourcie public @interface MyAnnotation {{ public @interface MyAnnotation String value(); String value(); }} @MyAnnotation( "Hello World" )) @MyAnnotation( "Hello World" @MyAnnotation( value == "Hello World" )) @MyAnnotation( value "Hello World"©Zenika 23
  • 24. Annotation personnalisées Paramètres dannotations • Comme dans toute interface, il est possible de définir des classes, interfaces ou enums internes public @interface MyAnnotation {{ public @interface MyAnnotation int defaultAnswer == 42; int defaultAnswer 42; int answer() default defaultAnswer; int answer() default defaultAnswer; enum Season {SPRING, SUMMER, FALL, WINTER}; enum Season {SPRING, SUMMER, FALL, WINTER}; Season season(); Season season(); }} @MyAnnotation( season == MyAnnotation.Season.WINTER )) @MyAnnotation( season MyAnnotation.Season.WINTER©Zenika 24
  • 25. Annotation personnalisées Les Méta-Annotations : @Target • La méta-annotation @Target indique sur quels éléments de code lannotation peut être apposée : @Target( ElementType[] )) @Target( ElementType[] public @interface MyAnnotation {{ public @interface MyAnnotation }} • Exemple : @Target( {ElementType.TYPE, ElementType.METHOD} )) @Target( {ElementType.TYPE, ElementType.METHOD} public @interface MyAnnotation {{ public @interface MyAnnotation }}©Zenika 25
  • 26. Annotation personnalisées Les Méta-Annotations : @Target • Valeurs possibles pour lenum ElementType : • TYPE • CONSTRUCTOR • FIELD • METHOD • PARAMETER • LOCAL_VARIABLE • ANNOTATION_TYPE (méta-annotation) • PACKAGE • TYPE_PARAMETER et TYPE_USE (JSR 308, Java 7 8?) Ex: @English String @NonEmpty [] • Si le paramètre nest pas spécifié, lannotation peut être utilisée partout (Ex : @Deprecated)©Zenika 26
  • 27. Annotation personnalisées Les Méta-Annotations : @Retention • La méta-annotation @Retention indique la durée de vie de lannotation @Retention( RetentionPolicy )) @Retention( RetentionPolicy public @interface MyAnnotation {{ public @interface MyAnnotation }} • Exemple @Retention( RetentionPolicy.RUNTIME )) @Retention( RetentionPolicy.RUNTIME public @interface MyAnnotation {{ public @interface MyAnnotation }}©Zenika 27
  • 28. Annotation personnalisées Les Méta-Annotations : @Retention • Valeurs possibles pour lenum RetentionPolicy : • SOURCE • CLASS (par défaut) • RUNTIME compilation class loading SOURCE CLASS RUNTIME©Zenika 28
  • 29. Annotation personnalisées Les Méta-Annotations : @Inherited • La méta-annotation @Inherited indique que lannotation est héritée par les classes filles de la classe annotée @Inherited @Inherited public @interface MyAnnotation {{ public @interface MyAnnotation }} • Restrictions • Seules les annotations portées sur les classes sont héritées • Les annotations apposées sur une interface ne sont pas héritées par les classes implémentant cette interface ; idem pour les packages.©Zenika 29
  • 30. Annotation personnalisées Les Méta-Annotations : @Documented • La méta-annotation @Documented indique que lannotation doit apparaître dans la javadoc @Documented @Documented public @interface MyAnnotation {{ public @interface MyAnnotation }}©Zenika 30
  • 31. Annotation personnalisées Démos Démos • Développer une annotation •Décompiler une annotation©Zenika 31
  • 32. Plan • Présentation • Anatomie • Mode demploi • Annotations personnalisées • Outillage compile-time • Historique et use-cases • Processus de compilation • Anatomie dun processeur • Limitations • Outillage runtime • Injection dannotations • Conclusion©Zenika 32
  • 33. Outillage compile-time Historique et use-cases Historique • Java 5.0 : APT (Annotation Processing Tool) • Devait être lancé en plus du compilateur javac • Java 6.0 : Pluggable Annotation Processors • Intégrés au processus de compilation standard • Paramètre -processor ou utilisation du SPI (Service Provider Interface) Pour plus dinformations sur le SPI, voir : • Un article sur The Coders Breakfast • La Javadoc de java.util.ServiceLoader©Zenika 33
  • 34. Outillage compile-time Historique et use-cases Use-cases • Génération de ressources : "XDoclet ++" • Fichiers de configuration • Classes annexes •Ex: Proxies, PropertyEditors... • Documentation •Ex: Matrice des rôles JavaEE, cartographie dIOC... • Amélioration du compilateur • Vérification de normes de codage •Ex: Les classes "modèle" doivent être Serializable... • Messages dalerte ou derreur supplémentaires©Zenika 34
  • 35. Outillage compile-time Historique et use-cases Mention spéciale : Lombok (projectlombok.org) • Améliore "magiquement" les classes •Génère les getters/setters, equals/hashCode, toString • Viole la règle de non-modification des ressources existantes • Dépend des implémentations internes des compilateurs pour manipuler les AST des classes •com.sun.tools.javac.* •org.eclipse.jdt.internal.compiler.* • Danger : la compilation de votre projet dépend désormais du support de votre compilateur cible par Lombok. Peser le rapport gain / risques ! •Votre IDE propose également ces fonctionnalités©Zenika 35
  • 36. Outillage compile-time Processus de compilation 1. Le compilateur découvre les processeurs dannotations •Paramètre -processor sur la ligne de commande •ou via le Service Provider Interface (SPI) 2. Un round de compilation est lancé •Le compilateur et les processeurs sexécutent •Si de nouvelles ressources sont créées lors de ce round, un nouveau round est lancé©Zenika 36
  • 37. Outillage compile-time Anatomie dun Processeur • Un processeur est une classe implémentant linterface javax.annotation.processing.Processor • Généralement, on sous-classe AbstractProcessor • Lannotation @SupportedAnnotationTypes permet dindiquer quelles annotations le processeur sait traiter • La méthode init() permet dinitialiser le processeur • La méthode principale process() reçoit un paramètre de type RoundEnvironment représentant lenvironnement de compilation. Elle renvoie un booléen indiquant si lannotation est définitivement "consommée" par ce processeur©Zenika 37
  • 38. Outillage compile-time Anatomie dun Processeur • Des utilitaires sont accessibles via la propriété processingEnv fournie par AbstractProcessor : • Types et Elements, permettant dintrospecter le code • Messager, pour lever des erreurs de compilation et afficher des messages dans la console • Filer, autorisant la création de nouvelles ressources (classes, fichiers de configuration...) Types Types types types == processingEnv.getTypeUtils(); processingEnv.getTypeUtils(); Elements Elements elts elts == processingEnv.getElementUtils(); processingEnv.getElementUtils(); Messager Messager messager messager == processingEnv.getMessager(); processingEnv.getMessager(); Filer Filer filer filer == processingEnv.getFiler(); processingEnv.getFiler();©Zenika 38
  • 39. Outillage compile-time Anatomie dun Processeur @SupportedAnnotationTypes("com.zenika.*") @SupportedAnnotationTypes("com.zenika.*") public class MyProcessor extends AbstractProcessor {{ public class MyProcessor extends AbstractProcessor Types types; Types types; Elements elements; Elements elements; Messager messager; Messager messager; Filer filer; Filer filer; public void init(ProcessingEnvironment processingEnv) {{ public void init(ProcessingEnvironment processingEnv) super.init(processingEnv); super.init(processingEnv); types types == processingEnv.getTypeUtils(); processingEnv.getTypeUtils(); elements == processingEnv.getElementUtils(); elements processingEnv.getElementUtils(); messager == processingEnv.getMessager(); messager = processingEnv.getFiler(); processingEnv.getMessager(); filer filer = processingEnv.getFiler(); }} public boolean process( public boolean process( Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {annotations, Set<? extends TypeElement> RoundEnvironment roundEnv) { // TODO }} // TODO }}©Zenika 39
  • 40. Outillage compile-time Anatomie dun Processeur public boolean process( public boolean process( Set<? extends TypeElement> annotations, Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {{ RoundEnvironment roundEnv) // Pour chaque annotation traitée... // Pour chaque annotation traitée... for (TypeElement annotation :: annotations) {{ for (TypeElement annotation annotations) // Trouver les éléments portant cette annotation // Trouver les éléments portant cette annotation for (Element ee :: for (Element roundEnv.getElementsAnnotatedWith(annotation)) {{ roundEnv.getElementsAnnotatedWith(annotation)) messager.printMessage( messager.printMessage( Diagnostic.Kind.NOTE, Diagnostic.Kind.NOTE, e.getSimpleName()); e.getSimpleName()); }} }} return false; return false; }}©Zenika 40
  • 41. Outillage compile-time Limitations • Développer un processeur est complexe ! • Les Types et les Elements offrent deux vues différentes sur le code compilé •Les Elements représentent lAST brut du code •Les Types offrent une interface davantage typée "java" •Il existe des ponts entre ces deux univers • Le pattern Visiteur est beaucoup utilisé • Un processeur ne peut pas modifier du code existant ! • Quelques bugs encore, et un faible support dans les IDE©Zenika 41
  • 42. Outillage compile-time Démos Démos • ListingProcessor •MessageHolderProcessor •SerializableClassesProcessor©Zenika 42
  • 43. Plan • Présentation • Annotations, mode demploi • Annotations personnalisées • Outillage compile-time • Outillage runtime • Use-cases • Récupération des paramètres • Une fois les annotations récupérées... • Injection dannotations • Conclusion©Zenika 43
  • 44. Outillage runtime Use-cases • Au runtime, il est possible dutiliser la Réflexion pour découvrir les annotations présentes sur les classes, champs, méthodes et paramètres de méthodes. • Uniquement si @Retention(RetentionPolicy.RUNTIME) • Use-cases : • Mapping Java ↔ ? • Programmation orientée POJO • Configuration de containers / frameworks • Exemples : • Hibernate, Apache CXF, XStream... • Spring, Guice, Java EE 5/6 (CDI, EJB 3.0, Servlets 3.0...)©Zenika 44
  • 45. Outillage runtime Récupération des annotations • Les classes Package, Class, Constructor, Field et Method implémentent linterface AnnotatedElement : public interface AnnotatedElement {{ public interface AnnotatedElement Annotation[] getAnnotations(); Annotation[] getAnnotations(); Annotation[] getDeclaredAnnotations(); Annotation[] getDeclaredAnnotations(); boolean isAnnotationPresent(Class annotationClass); boolean isAnnotationPresent(Class annotationClass); Annotation getAnnotation(Class annotationClass); Annotation getAnnotation(Class annotationClass); }} • getAnnotations() renvoie toutes les annotations applicables à lélément, y compris les annotations héritées • getDeclaredAnnotations() ne renvoie que les annotations directement apposées sur lélément©Zenika 45
  • 46. Outillage runtime Récupération des annotations • Exemple : lecture des annotations dune classe et de celles de son package // Annotations sur la classe // Annotations sur la classe Annotation[] clsAnnots == Pojo.class.getAnnotations(); Annotation[] clsAnnots Pojo.class.getAnnotations(); for (Annotation annot :: clsAnnots) {{ for (Annotation annot clsAnnots) System.out.println(annot); System.out.println(annot); }} // Annotations sur le package // Annotations sur le package Package pkg == Pojo.class.getPackage(); Package pkg Pojo.class.getPackage(); Annotation[] pkgAnnots == pkg.getDeclaredAnnotations(); Annotation[] pkgAnnots pkg.getDeclaredAnnotations(); for (Annotation annot :: pkgAnnots) {{ for (Annotation annot pkgAnnots) System.out.println(annot); System.out.println(annot); }}©Zenika 46
  • 47. Outillage runtime Récupération des annotations • Les classes Constructor et Method permettent également de récupérer les annotations présentes sur leurs paramètres • Annotation[][] getParameterAnnotations() • Renvoie un tableau dannotations par paramètre, dans lordre de leur déclaration dans la signature de la méthode public void printParamAnnots(Method method) {{ public void printParamAnnots(Method method) Annotation[][] allAnnots == Annotation[][] allAnnots method.getParameterAnnotations(); method.getParameterAnnotations(); for (Annotation[] annots :: paramAnnots) {{ for (Annotation[] annots paramAnnots) System.out.println(Arrays.toString(annots)); System.out.println(Arrays.toString(annots)); }} }}©Zenika 47
  • 48. Outillage runtime Une fois les annotations récupérées... • Que peut-on faire avec les annotations récupérées par réflexion ? • On peut découvrir leur type dynamiquement Class<? extends Annotation> annotationType() • On peut lire leurs paramètres (cast nécessaire) Annotation annot == …… ;; Annotation annot // Détermination du type réel de lannotation // Détermination du type réel de lannotation Class<? extends Annotation> annotClass == Class<? extends Annotation> annotClass myAnnotation.annotationType(); myAnnotation.annotationType(); // Affichage du message de MyAnnotation // Affichage du message de MyAnnotation if (annot instanceof MyAnnotation) {{ if (annot instanceof MyAnnotation) MyAnnotation myAnnot == (MyAnnotation) annot; MyAnnotation myAnnot (MyAnnotation) annot; System.out.println(myAnnot.message()); System.out.println(myAnnot.message()); }}©Zenika 48
  • 49. Outillage runtime Démos Démos • Démonstration • Exemple : CSVReader©Zenika 49
  • 50. Plan • Présentation • Mode demploi • Annotations personnalisées • Outillage compile-time • Outillage runtime • Injection dannotations • Au coeur de la classe Class • Instancier dynamiquement une annotation • Injection dans une classe • Injection sur une méthode ou un champ • Conclusion©Zenika 50
  • 51. Injection dannotations Au coeur de la classe Class • Dans la classe Class, les annotations sont représentées sous la forme de Maps : private transient Map<Class, Annotation> annotations; private transient Map<Class, Annotation> annotations; private transient Map<Class, Annotation> declaredAnnotations; private transient Map<Class, Annotation> declaredAnnotations; • Ces maps sont initialisées lors du premier appel à getAnnotations() ou getDeclaredAnnotations() • Linitialisation est réalisée en décodant le byte[] renvoyé par la méthode native getRawAnnotations() • En modifiant ces maps par Réflexion, il est possible dinjecter arbitrairement des annotations sur une Classe au runtime !©Zenika 51
  • 52. Injection dannotations Instancier une annotation • Pour obtenir une instance de lannotation à injecter, il suffit dinstancier une classe anonyme implémentant son "interface" MyAnnotation myAnnotation == new MyAnnotation() {{ MyAnnotation myAnnotation new MyAnnotation() @Override @Override public String message() {{ public String message() return MyAnnotation.defaultMessage; }} return MyAnnotation.defaultMessage; @Override @Override public int answer() {{ public intMyAnnotation.defaultAnswer; answer() return MyAnnotation.defaultAnswer; }} return @Override @Override public Class<? extends Annotation> annotationType() {{ public Class<? extends Annotation> annotationType() return MyAnnotation.class; }} return MyAnnotation.class; }; };©Zenika 52
  • 53. Injection dannotations Injection sur une Classe • Il ne reste plus quà utiliser la Réflexion pour injecter notre annotation dans la classe cible public static void injectClass public statictargetClass, Annotation annotation) { void injectClass (Class<?> targetClass, Annotation annotation) { (Class<?> // Initialisation des maps dannotations // Initialisation des maps dannotations targetClass.getAnnotations(); targetClass.getAnnotations(); // Récupération de la map interne des annotations // Récupération de la map interne des annotations Field mapRef == Class.class.getDeclaredField("annotations"); Field mapRef Class.class.getDeclaredField("annotations"); mapRef.setAccessible(true); mapRef.setAccessible(true); // Modification de la map des annotations Map<Class, Annotation> map des=annotations // Modification de la annots Map<Class, Annotation> annots = (Map<Class, Annotation>) mapRef.get(targetClass); if (annots==null Annotation>) mapRef.get(targetClass); (Map<Class, || annots.isEmpty()) { if annots = new HashMap<Class, Annotation>(); (annots==null || annots.isEmpty()) { }} annots = new HashMap<Class, Annotation>(); pojoAnnotations.put(annotation.annotationType(), annotation); pojoAnnotations.put(annotation.annotationType(), annotation); mapRef.set(targetClass, pojoAnnotations); }} mapRef.set(targetClass, pojoAnnotations);©Zenika 53
  • 54. Injection dannotations Injection sur une Méthode ou un Champ • Linjection dannotations sur les classes Constructor, Field et Method est plus problématique • Au sein de la classe Class, les méthodes getConstructor(), getField(), ou getMethod() renvoient des copies des objets correspondants Method m1 == Pojo.class.getDeclaredMethod("foo", null); Method m1 Pojo.class.getDeclaredMethod("foo", null); Method m2 == Pojo.class.getDeclaredMethod("foo", null); Method m2 Pojo.class.getDeclaredMethod("foo", null); System.out.println(m1==m2); // false System.out.println(m1==m2); // false • Ces copies sont initialisées directement à partir du bytecode de la classe, pas à partir dune instance prééxistante • Les modifications apportées aux maps dannotations sur une instance sont donc strictement locales à cette instance©Zenika 54
  • 55. Injection dannotations Injection sur une Méthode ou un Champ • Alors, comment faire ? • AOP pour intercepter les méthodes getConstructor(), getMethod(), getField() ? • Modifier directement la portion de bytecode correspondant à ces objets ? • Si vous trouvez une solution, je suis preneur !©Zenika 55
  • 56. Injection dannotations Use-cases • Use-cases • Les annotations @Inherited posées sur les interfaces ne sont pas héritées par les classes implémentant ces interfaces. Il est possible dy remédier en réinjectant manuellement ces annotations dans les classes. Mais attention aux conflits ! • … dautres idées ?©Zenika 56
  • 57. Injection dannotations Démos Démos • Injection dans une classe • Injection dans un champ©Zenika 57
  • 58. Plan • Présentation • Mode demploi • Annotations personnalisées • Outillage compile-time • Outillage runtime • Injection dannotations • Conclusion©Zenika 58
  • 59. Conclusion • Les doclets ont ouvert la voie à la méta-programmation ; Java 5.0 a standardisé et démocratisé les annotations • Tous les frameworks modernes utilisent les annotations • Elles complètent parfaitement les fichiers de configuration XML • Il est facile de développer des annotations personnalisées • Java fournit des outils pour les exploiter lors de la compilation et au runtime • Mais attention à la complexité !©Zenika 59
  • 60. ? Conclusion Questions / Réponses©Zenika 60
  • 61. Références • Annotation processors • La documentation du SDK et la JLS • "Enforcing design rules with Pluggable Annotation Processors" sur http://thecodersbreakfast.net • La newsletter Javaspecialists (http://javaspecialists.eu) • JSR 308 et le framework Checkers • http://types.cs.washington.edu/jsr308/ • Lombok • http://projectlombok.org/©Zenika 61

×