Mis à jour le mercredi 30 novembre 2016
  • 6 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

TP : L'annotation @Todos

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Dans ce TP, je vous propose d'étoffer un peu ce que nous avons fait dans le chapitre précédent.
Il n'y aura rien d'insurmontable mais c'est bon de pratiquer. :)

Cahier des charges

Voici ce que je vais vous demander de faire :

  • une annotation s'appelant Todos qui prendra en élément un tableau de Todo, que nous avons fait dans le chapitre précédent.

  • Un processeur capable de traiter des annotations TodoetTodos pour sortir un fichier HTML.

Voici des classes, déjà annotées, qu'il faudra traiter :

package com.sdz.classes;

import com.sdz.annotation.NIVEAU;
import com.sdz.annotation.Todo;
import com.sdz.annotation.Todos;

public class MaClasse1 {

   @Todos(
      {
         @Todo(   auteur = "zozor",
                  niveau = NIVEAU.AMELIORATION,
                  commentaire = "Tu ferais mieux d'utiliser un double...", 
                  destinataire = "cysboy"),
         @Todo(
               commentaire = "Utiliser l'annotation @SuppressWarning", 
               destinataire = "cysboy")
      }
   )
   private short entier = 0;

   public MaClasse1(){ }   
   
   @Todos(
         {
            @Todo(
                  commentaire = "Qu'est-ce que c'est que cette méthode ?", 
                  destinataire = "zozor",
                  niveau = NIVEAU.CRITIQUE)
         }
   )
   public void zozorEstPasseeParLa(){ }  
}
package com.sdz.classes;

import com.sdz.annotation.NIVEAU;
import com.sdz.annotation.Todo;
import com.sdz.annotation.Todos;

@Todo(
      niveau = NIVEAU.CRITIQUE,
      commentaire = "Il faudrait penser à terminer la classe.", 
      destinataire = "zozor"
)
public class MaClasse2 extends MaClasse1{

   @Todos(
         {
            @Todo(
                  commentaire = "Mais que fait cette méthode ?", 
                  destinataire = "zéro",
                  niveau = NIVEAU.BUG),
            @Todo(
                  commentaire = "Pourquoi tant de N !", 
                  destinataire = "cysboy",
                  niveau = NIVEAU.AMELIORATION)
         }
   )
   public String doSomething(){
      return "something :p ";
   }
}
package com.sdz.classes;

import com.sdz.annotation.NIVEAU;
import com.sdz.annotation.Todo;
import com.sdz.annotation.Todos;

public class MaClasse3 {

   @Todos(
         {
            @Todo(
                  commentaire = "Penser à faire les initialisations...", 
                  destinataire = "zozor",
                  niveau = NIVEAU.BUG),
            @Todo(
                  commentaire = "Aucune gestion d'exception ! ", 
                  destinataire = "zozor",
                  niveau = NIVEAU.AMELIORATION)
         }
   )
   public void doSomething( 
         @Todo(
               niveau = NIVEAU.BUG,
               commentaire = "Vérifier le contenu de ce paramètre", 
               destinataire = "cysboy"
         )
         String str){
      //....
   }   
}

Et voici un exemple de résultat :

Résultat possible

Allez, à vos claviers. ^^

Correction

Stop !
Alors ! Vous vous en êtes sortis ? Voici une correction possible pour ce TP.

L'annotation @Todos

package com.sdz.annotation;

public @interface Todos {
   Todo[] value();
}

Les méta-annotations que j'avais utilisées précédemment n'étaient là que dans un but pédagogique et donc pas vraiment nécessaires. C'est pourquoi je ne les ai pas mises ici.

TodosHTMLProcessor.java

package com.sdz.processors;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

import com.sdz.annotation.Todo;
import com.sdz.annotation.Todos;

//Permet de spécifier les annotations à traiter
@SupportedAnnotationTypes(value = { 
               "com.sdz.annotation.Todos",
               "com.sdz.annotation.Todo"
              }
)
//Définit quelle version de source gérer, ici je code en Java 7
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class TodosHTMLProcessor extends AbstractProcessor {
   
  List<Todo> list = new ArrayList<>();;
  FileOutputStream fw = null;
  
  @Override
  public boolean process(
      Set<? extends TypeElement> annotations,
      RoundEnvironment roundEnv) {
      
    System.out.println("Début du traitement HTML !");
    
    //tout ceci est identique à l'autre processeur
    for (TypeElement te : annotations) {
 
      for (Element element : roundEnv.getElementsAnnotatedWith(te)) {
        
         Todos todos = element.getAnnotation(Todos.class);
         
        //Si l'annotation est de type Todos
        if(todos != null){
           
           System.out.println("Annotation Todos trouvée.");
           //On récupère l'annotation et on traite son contenu
           //en utilisant une boucle
           for(Todo todo : todos.value())
              this.addToList(todo);
        }
        else{
           System.out.println("Annotation Todo simple trouvée.");
           //sinon, on traite normalement
           Todo todo = element.getAnnotation(Todo.class);
           this.addToList(todo);
        }
      }
    }
    System.out.println("Fin du traitement HTML");
    
    //Génération du fichier HTML
    genererHTML(list);
    return true;
  }
  
  private void addToList(Todo todo){
     if(todo != null)
        this.list.add(todo);
  }
  
  private void genererHTML(List<Todo> list){
     
     StringBuilder html = new StringBuilder();
     html.append("<html>");     
     html.append("<body>");
     html.append("<table>");
     
     html.append("<tr>");
     html.append("<td style=\"border:1px solid black\">Criticité</td>");
     html.append("<td style=\"border:1px solid black\">Auteur</td>");
     html.append("<td style=\"border:1px solid black\">Destinataire</td>");
     html.append("<td style=\"border:1px solid black\">Commentaire</td>");
     html.append("</tr>");
     
     Iterator<Todo>  it = list.iterator();
     
     if(list.isEmpty())return;
     
     File htmlFile = new File("Todo.html");
     
     try {
        fw = new FileOutputStream(htmlFile);
     } catch (IOException e) {
       e.printStackTrace();
     }
     
     while(it.hasNext()){
        
        Todo todo = it.next();
        html.append("<tr>");
        String style = "";
        
        //Voilà à quoi sert le nouveau champ de mon énumération
        switch(todo.niveau().getLevel()){
           case 0 : 
              style = "style=\"color:green;border:1px solid black\"";
           break;
           case 1:
              style = "style=\"color:purple;border:1px solid black\"";
           break;
           case 2:
              style = "style=\"color:orange;border:1px solid black\"";
           break;
           case 3:
              style = "style=\"color:red;border:1px solid black\"";
           break;
        }
        
        html.append("<td " + style + ">" + todo.niveau() + "</td>");
        html.append("<td " + style + ">" + todo.auteur() + "</td>");
        html.append("<td " + style + ">" + todo.destinataire() + "</td>");
        html.append("<td " + style + ">" + todo.commentaire() + "</td>");
        html.append("</tr>");
     }
     
     html.append("</table>");
     html.append("</body>");     
     html.append("</html>");

     //On écrit dans le fichier et voilà !
     try {
      fw.write(html.toString().getBytes());
     } catch (IOException e) { 
      e.printStackTrace();
     }finally{
        try{
           fw.close();
        } catch (IOException ex) { 
           ex.printStackTrace();
           
        }
     }
  }  
}

Ensuite, il faut donc créer un fichier .jar, générer la liste des classes à traiter et lancer la commande javac avec les paramètres vus dans le chapitre précédent et le tour est joué. :magicien:

Alors, je vous l'avais bien dit qu'il n'y avait rien d'insurmontable.
Maintenant que vous êtes familier de ce genre de choses, je vous propose de voir une autre manière d'utiliser des annotations avec notre langage préféré. :)

Exemple de certificat de réussite
Exemple de certificat de réussite