TD4 - Annotations

De $1

Ce TD propose la création d'annotations, leur manipulation par introspection et avec l'interface APT de manipulation des annotations. 

Annotation Menu

Créez une annotation de nom @Menu qui s'applique uniquement sur les méthodes (cf. Meta-annotation @Target) et qui sera utilisée aussi bien lors de la compilation que dynamiquement par introspection (cf. Meta-Annotation@Retention). Cette annotation doit permettre de construire automatiquement un menu dans une fenêtre. 

Un menu (ex: JMenu) possède:

  • Un nom
  • [Optionnel] Une icône (chargée à partir d'un fichier image : ImageIcon)
  • [Optionnel] Une combinaison clavier pour un raccourci clavier (voir la méthode statique KeyStroke.getKeyStroke)
  • Un comportement (c'est-à-dire une méthode qui s'exécute lorsque l'on clique sur le menu)

Utiliser une annotation plutôt que la classe JMenu directement permet de s'affranchir de l'environnement graphique à utiliser. Si plus tard on décide d'utiliser AWT ou SWT au lieu de Swing, l'information sur le menu reste présente sous forme d'annotation.

Introspection et annotations

Reprenez l'exercice sur les Menu du TD3.

Spécialisez la classe FrameWithMenu et redéfinir la méthode buildMenu() pour créer les menus en fonction de l'annotation @Menu.

  • On chargera donc (dynamiquement) toutes les classes (fichiers .class) qui se trouvent dans le repository (Utilisez la classe Repository du TD3).
  • On sélectionnera par introspection celles qui ont des méthodes annotées par @Menu. Il peut y avoir plusieurs méthodes annotées ! On vérifiera cependant que ces méthodes sont statiques, publiques et sans paramètres. Pour chacune des méthodes sélectionnées, il faut utiliser l'information de l'annotation pour
    • créer un menu
    • Si le nom n'est pas donné par un champ spécifique, on utilisera le nom de la méthode
    • On chargera la bonne icône et le bon raccourci clavier
    • On utilisera la méthode invoke pour exécuter cette méthode lorsque l'utilisateur clique sur le menu ainsi créé.

Par exemple, avec la classe suivante dans mon repository:

class MonMetier {
 @Menu(name="action", icon="res/icon.png", shortcut="control A")
 public static void monSavoirFaire() {
  System.out.println("C'est mon métier.");
 }
}

Il faudra créer un menu de nom "action", avec l'icône contenue dans le fichier "res/icon.png" et la touche de raccourci "CTRL-A". Un clic sur ce menu devra exécuter la méthode monSavoirFaire, l'équivalent par introspection deMonMetier.monSavoirFaire();

Annotation Processing Tool

Dans l'exercice précédent, on a besoin que les méthodes soient publiques, statiques et sans paramètres. Plutôt que de s'apercevoir dynamiquement que ce n'est pas le cas, on voudrait disposer d'un moyen pour s'en apercevoir à la compilation, voire à l'édition. L'outil APT (Annotation Processing Tool) est là pour nous aider.

Assistance à la compilation

Utilisez l'APT pour s'assurer à la compilation que les méthodes annotées par @Menu sont bien publiques, statiques et sans paramètres. Si ce n'est pas le cas, on enverra un message dans le Messager. Il vous faut créer :

Attention pour compiler vous devez obligatoirement mettre dans votre classpath le fichier $JDK_HOME/lib/tools.jar qui est livré avec le JDK. Pour tester votre travail vous devez utiliser la commande "apt" livrée avec le JDK Java [Slide 47 du cours].

Génération de code : patron Adaptateur

Dans l'exercice 2 de ce TP, on créé dynamiquement une  AbstractAction (avec une classe anonyme) pour chaque méthode annotée. Plutôt que d'utiliser l'introspection (qui coûte chère et qui est source d'erreurs dynamiques) on préfèrerait écrire une classe ad-hoc pour chaque méthode à exécuter (comme on faisait au TD3). Au lieu de le faire manuellement (c'est fastidieux et source d'erreur), on va (vous allez) utiliser le mécanisme de génération de code de l'APT pour le faire à la compilation automatiquement.

Vous pouvez repartir du code de l'exercice précédent et utiliser la classe Filer. A vous !

Il s'agit en fait de créer un adaptateur qui adapte la méthode annotée à l'interface exigée par les JMenu. Vous pouvez également tester la génération avec la commande "apt" [Slide 47 du cours]. Une intégration dans Eclipse est proposée dans la section suivante.

Assistance à l'édition (Eclipse uniquement)

L'utilisation de l'outil apt à partir de la ligne de commande est un peu fastidieuse. Heureusement les IDEs modernes ont intégré ce mécanisme dans leur chaîne de compilation. Ce TD donne quelques indications pour faire le travail dans Eclipse. NetBeans propose des mécanismes similaires.

Il faut disposer d'un Eclipse (par exemple la dernière version Indigo) pour Java.

Il faut mettre à jour pour disposer du plugin PDE, c'est l'environnement Eclipse pour développer de nouveaux plugins.

Il est impossible de réaliser cet exercice avec un seul projet. Utilisez les Working Sets pour grouper les projets de thèmes similaires. Vous aurez besoins de trois projets :

  • un projet Java qui contient votre annotation (sa définition)
    • Ce projet sera exporté dans un fichier menu.jar"Clic droit/Export.../Jar file" dans lequel on ne mettra que le .class, pas besoin du source
  • un projet Plugin qui contient votre usine, votre processeur d'annotations et le visiteur. Ce projet doit dépendre du plugin org.eclipse.jdt.apt.core
    • créer un projet de Plugin (sans Wizard)
    • cliquez sur plugin.xml ou META-INF/MANIFEST.MF
    • ajouter la dépendance vers org.eclipse.jdt.apt.core avec l'onglet Dependencies
    • enregistrer votre usine en créant une extension (onglet Extensions)
      • Add... org.eclipse.jdt.apt.core.annotationProcessorFactory
      • Clic droit (sur la ligne qui vient d'apparaître) New -> factories
      • Sélectionner true dans le menu déroulant enableDefault
      • Clic droit (sur factories) New -> factory
      • Sélectionner dans la zone de texte "class*" votre usine avec le menu "Browse".
    • ce type de projet ne s'exécute pas comme un projet Java mais comme une application Eclipse: "Run As/Eclipse Application" (ou Debug As). Ceci a pour effet de lancer un second workspace dans lequel on peut tester et débugger le plugin (avant déploiement).
  • un projet Java dans le workspace de debug et qui utilise le plugin déployé
    • Ce projet doit contenir le fichier menu.jar dans son Build Path : "Clic droit/Build Path/Configure Build Path"
    • Il faut aussi configurer le projet pour qu'il reconnaisse l'usine à utiliser
      • Sélectionnez le projet
      • Clic droit/Properties
      • Dans "Java Compiler/Annotation Processing", sélectionnez "Enable project specific settings""Enable annotation processing""Enable processing in editor". Constater que le dossier de génération s'appelle par défaut.apt_generated
      • Dans "Java Compiler/Annotation Processing/Factory path", sélectionnez "Enable project specific settings" et cocher la case qui correspond à votre plugin. Si le plugin n'est pas là, c'est que votre plugin a mal été déployé. Le nom qui s'affiche est l'identificateur qui a été choisi dans le plugin.xml.
      • Cliquez sur "Apply" et confirmez qu'il faut recompiler
      • Utilisez votre annotation sur une méthode et vérifiez que cela fonctionne comme attendu.
    • A chaque fois que le fichier est modifié et qu'il contient la bonne annotation, le visiteur vérifie que la méthode a la bonne syntaxe et le code est généré.

Félicitations vous avez déployé votre premier plugin Eclipse !