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 !

Généralités

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

Même si je suis persuadé que vous les avez déjà rencontrées, dans ce chapitre nous allons faire la connaissance de ces fameuses annotations.
Je vous présenterai les grandes lignes sur leurs fonctions et leurs utilisations et je vous montrerai leurs différences avec la JavaDoc.

Nous verrons qu'il existe plusieurs catégories d'annotations et qu'il est possible de faire beaucoup de choses grâce à elles.

Bon ! Qu'attendons-nous pour commencer !

Comment fonctionnent les annotations ?

Comme je vous l'ai dit un peu plus tôt, les annotations permettent de rajouter des métadonnées dans vos codes sources (on parle aussi d'ajout sémantique). Elles peuvent être utilisées sur plusieurs composantes de vos programmes Java :

  • sur des classes ;

  • sur des méthodes ;

  • sur des interfaces ;

  • sur des variables ;

  • sur des packages.

Ces fameuses données sémantiques peuvent être lues par des programmes comme des générateurs de JavaDoc mais elles sont aussi lues par le compilateur Java qui peut aussi permettre leur utilisation grâce à l'introspection. Vous pouvez même interagir avec le compilateur grâce à un utilitaire ajouté avec les annotations dans Java : Pluggable Annotation-Processing API.

C'est un peu flou tout ce que tu viens de nous dire là...

Oui, je le sais mais les choses deviendront plus claires dans quelques instants...
Pour que vous puissiez mieux comprendre, imaginez que les annotations servent principalement à marquer certains éléments du langage Java afin de leur attribuer des données particulières (voir même des actions). De plus, les annotations peuvent être utilisées à différents moments du cycle de vie d'un programme :

  • lors de son écriture : les annotations peuvent être utilisées pour documenter et donner des informations aux différents développeurs ;

  • lors de la compilation : cela permet d'interagir avec le compilateur et lui faire exécuter des tâches automatiquement ;

  • pendant l'exécution du programme : en utilisant l'introspection, vous pouvez accéder aux annotations et agir sur vos méthodes, vos champs, vos classes...

D'accord, mais concrètement, qu'est-ce que c'est ?

Pour vous faire voir un exemple d'annotation, je vous propose de créer une simple classe Java dans Eclipse, comme ceci :

public class TestAnnotation {
   private String nom = "toto";
}

Maintenant, demandez à Eclipse de générer la méthode toString(). Ceci se fait en allant dans le menu "Source/Generate toString()", ce qui nous donne :

public class TestAnnotation {
   private String nom = "toto";

   @Override
   public String toString() {
      return "TestAnnotation [nom=" + nom + "]";
   }
}

Voilà, @Override est une annotation, nous verrons bientôt à quoi elle sert mais au moins, vous savez à quoi ça ressemble. :-°

C'est comme un commentaire JavaDoc !

Et non !
Pour que vous puissiez bien comprendre, je vais vous montrer une autre annotation qui a son homologue en commentaire JavaDoc :

public class TestAnnotation {
   private String nom = "toto";

   /**
    * Les instructions JavaDoc sont dans les commentaires
    * Alors que les annotations sont en dehors de tous blocs de commentaires
    * @deprecated
    * @return
    */
   @Deprecated
   public String faisQuelqueChose(){
      return "Je ne fais rien...";
   }
}

Vous pouvez voir que l'annotation ne se trouve pas dans le bloc JavaDoc et que celle-ci commence par une majuscule, alors que l'instruction JavaDoc, elle, commence par une minuscule...

Pour le moment, retenez qu'il existe plusieurs types d'annotations :

  • les annotations marqueurs : on parle aussi d'annotations standards. Ce sont des marqueurs placés qui permettent au compilateur de faire ou ne pas faire certaines actions. On trouve notamment @Override, @Deprecated, @SuppressWarning...

  • les annotations paramétrées : ce sont des annotations qui prennent un paramètre pour pouvoir fonctionner. Nous verrons l'annotation @Retention(RetentionPolicy.RUNTIME);

  • les annotations multiparamétrées : ces dernières prennent plusieurs paramètres.

Le langage Java vous propose déjà des annotations de ces trois types que vous pouvez utiliser dans vos programmes.
Une annotation se construit comme une interface avec une petite subtilité...
Vous pouvez utiliser Eclipse pour vous aider à la créer en faisant "File/New/Annotation" ou en choisissant directement dans la barre d'outils, comme ceci :

Image utilisateur

Voici un exemple d'annotation maison :

public @interface AnnotationZ {

}

Une fois ceci fait, vous pouvez utiliser votre annotation dans un de vos programmes, comme ceci :

public class TestAnnotation {
   private String nom = "toto";

   @AnnotationZ
   public String faisQuelqueChose(){
      return "Je ne fais rien...";
   }
   
   @AnnotationZ public String faisQuelqueChoseDAutre(){
      return "Je ne fais rien...";
   }
}

Pour utiliser une annotation, vous devez l'utiliser avant la chose que vous souhaitez annoter. Le code ci-dessus est conforme car l'annotation porte sur la méthode sous l'annotation, par contre, le code ci-dessous ne fonctionnera pas :

public class TestAnnotation {
   private String nom = "toto";

   @AnnotationZ
   public String faisQuelqueChose(){
      return "Je ne fais rien...";
   }
   
   public String faisQuelqueChoseDAutre(){
      return "Je ne fais rien...";
   }
   @AnnotationZ 
}

Par convention, on utilise la première syntaxe en ayant une annotation par ligne. Vous comprenez mieux pourquoi les annotations commencent par une majuscule maintenant : il s'agit d'une forme de classe donc elles respectent la convention de nommage Java.

Vous ne pouvez utiliser qu'une seule fois une annotation sur un élément du langage, ainsi, ce code ne pourra pas être compilé :

public class TestAnnotation {
   private String nom = "toto";

   @AnnotationZ
   @AnnotationZ
   public String faisQuelqueChose(){
      return "Je ne fais rien...";
   }
}

Pour le moment cette annotation ne fait absolument rien, nous verrons par la suite comment les utiliser...
Nous approfondirons tout ceci plus tard mais, pour le moment, je vous propose de voir les annotations standards et les méta-annotations.

Les méta-annotations

Ces annotations servent à marquer d'autres annotations, surtout pour indiquer au compilateur comment et quand il doit interpréter les annotations qui les utilisent. Ce type d'annotations va donc nous servir à créer nos propres annotations mais elles sont aussi utilisées par les annotations standards présentes dans le langage Java.

Toutes les annotations que nous allons voir maintenant ont un but bien précis et elles sont toutes présentes dans le package java.lang.annotation.

@Documented

Celle-ci indique à l'utilitaire JavaDoc que l'annotation doit être présente dans la documentation générée. Si nous reprenons l'annotation que je vous ai fait créer tout à l'heure, ceci pourrait se traduire ainsi :

import java.lang.annotation.Documented;

@Documented
public @interface AnnotationZ { }

Pour bien voir ce que cette annotation produit, créons une deuxième annotation témoin, comme ceci :

public @interface Temoin { }

Et nous allons utiliser ces deux annotations dans une classe, ainsi :

public class TestAnnotation {
   private String nom = "toto";
   
   /**
    * Commentaire Javadoc de la méthode, juste pour l'exemple
    * @return
    */
   @AnnotationZ 
   public String faisQuelqueChose(){
      return "Je ne fais rien...";
   }
   
   /**
    * Un autre commentaire JavaDoc
    * @return
    */
   @Temoin
   public String faisQuelqueChoseDAutre(){
      return "Je ne fais rien...";
   }
}

Il ne nous reste plus qu'à générer la JavaDoc de ces classes. Pour ce faire, allez dans le menu "Project/Generate Javadoc" :

Image utilisateur

Une popup Eclipse doit s'ouvrir et vous demander quelques informations :

Image utilisateur

Vous devez donc lui spécifier ou trouver l'utilitaire JavaDoc, moi j'ai pris celui fourni avec le JDK dans le dossier "bin" (voir encadré vert). 
Vous aurez aussi à déterminer quelles sont les classes à prendre en compte, moi, je les ai toutes prises (voir encadré orange).
Et enfin, vous devrez spécifier ou générer la documentation : j'ai choisi le dossier de mes programmes pour pouvoir les ouvrir avec Eclipse (voir encadré violet)...
Cliquez sur le bouton "Finish", patientez quelques secondes et vous devriez avoir tout un tas de nouveaux fichiers :

Image utilisateur

Ouvrez avec Eclipse le fichier "TestAnnotation.html" en faisant un clic-droit dessus puis "Open With/Web Browser" et voilà la JavaDoc de votre classe.
Si vous descendez un peu, vous verrez les deux méthodes et là :

Image utilisateur

Seule l'annotation marquée avec la méta-annotation @Documented est présente dans la JavaDoc : voilà à quoi sert cette annotation.

@Inherit

L'annotation @Inherit indique que tous les enfants d'une classe marquée avec une annotation, marquée elle-même avec cette méta-annotation, en hériteront. Pour faire simple, l'annotation doit-elle être héritée par les classes filles d'une classe marquée ?

Pour mieux vous expliquer, voici un exemple très simple en reprenant nos annotations de tests (l'annotation @Temoin ne change pas) :

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;

@Documented
@Inherited
public @interface AnnotationZ { }

Nous avons donc rajouté la méta-annotation dans notre annotation personnalisée.

@AnnotationZ
@Temoin
public class ClasseMere { }

Nous avons marqué une classe avec nos deux annotations.

public class ClasseFille extends ClasseMere{ }

Cette classe hérite de notre classe mère vue précédemment mais elle bénéficiera uniquement de l'annotation @AnnotationZ car l'annotation @Temoin n'est pas configurée pour gérer l'héritage de classe.

Eh ! J'ai regénéré la JavaDoc de mon projet, j'ai bien mon annotation dans ClasseMere mais pas dans ClasseFille !

Tout à fait, mais je vous assure que votre classe fille est bien marquée par notre annotation. Pour vous l'assurer, nous devons tout d'abord voir une autre méta-annotation et, ensuite, je vous proposerai un code de test et vous verrez que tel est bien le cas. :magicien:

@Retention

L'annotation @Retention permet de régler une "durée de vie" pour votre annotation, ce qui indique au compilateur comment il doit la gérer. Elle prend un paramètre qui se trouve dans l'énumération java.lang.annotation.RetentionPolicy, à savoir :

  • RetentionPolicy.CLASS : Les annotations seront enregistrées dans le fichier .class par le compilateur mais ils ne seront pas utilisables par la JVM au moment de l’exécution. Elles peuvent être utilisables par tout logiciel capable de travailler avec des fichiers .class. C'est le comportement par défaut du compilateur lorsqu'une classe est marquée d'une annotation dans laquelle cette métadonnée n'est pas spécifiée.

  • RetentionPolicy.RUNTIME : Les annotations seront enregistrées dans le fichier .class par le compilateur et seront utilisables par la JVM pendant l'exécution de votre programme, grâce à l'introspection.

  • RetentionPolicy.SOURCE : Les annotations ne seront pas enregistrées dans le fichier .class, par conséquent, elles ne pourront être utilisées que par des outils sachant lire des fichiers source, comme l'utilitaire JavaDoc, le compilateur...

Pour illustrer ceci, je vous propose déjà de compléter nos annotations persos ainsi :

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Temoin { }
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationZ { }

Maintenant, nos deux annotations sont utilisables grâce à l'introspection. Cependant, seule l'annotation @AnnotationZ sera documentée dans la JavaDoc.
Nous allons toutefois ajouter deux nouvelles annotations à notre panel, pour l'exemple :

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Documented
@Retention(RetentionPolicy.SOURCE)
public @interface AnnotationSource { }
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Documented
@Retention(RetentionPolicy.CLASS)
public @interface AnnotationClass { }

Si nous regénérons la JavaDoc, nous pouvons voir nos différentes annotations apparaître, enfin, seulement celles qui sont marquées avec l'annotation @Documented :

Image utilisateur
Image utilisateur

Maintenant, afin de vous montrer que les annotations marquées avec @Inherit sont bien disséminées dans la hiérarchie de classes, voici un code de test :

import java.lang.annotation.Annotation;

public class Test {
   public static void main(String[] args) {      
      
      //Nous pouvons récupérer les différentes annotations
      //grâce à la méthode getAnnotations() de l'objet Class
      System.out.println("Annotations utilisables pour la classe ClasseMere : "); 
      for(Annotation a : ClasseMere.class.getAnnotations())
         System.out.println("\t * " + a.annotationType());
      
      
      System.out.println("---------------------------------------------------");
      System.out.println("Annotations utilisables pour la classe ClasseFille : ");
      //Une autre manière de faire, avec une instance cette fois
      ClasseFille cFille = new ClasseFille();
      for(Annotation a : cFille.getClass().getAnnotations())
         System.out.println("\t * " + a.annotationType());
   }
}

Qui nous donne ceci :

Annotations utilisables pour la classe ClasseMere : 
         * interface AnnotationZ
         * interface Temoin
---------------------------------------------------
Annotations utilisables pour la classe ClasseFille : 
         * interface AnnotationZ

Vous pouvez voir que notre annotation @AnnotationZ est bien présente et utilisable dans l'objet ClasseFille (même si elle n'apparaît pas dans la JavaDoc) et que les deux autres annotations, marquées comme non utilisables pendant l'exécution du programme, ne sont pas accessibles.

@Target

La méta-annotation @Target permet de cibler sur quels éléments du langage nous pourrons utiliser des annotations.
Tout comme l'annotation précédente, celle-ci accepte un paramètre qui est représenté par une énumération présente dans le package java.lang.annotation.ElementType et qui définit quel type de données nous pouvons annoter.
Voici un tableau qui liste le contenu de l'énumération :

Valeur

Description

ElementType.PACKAGE

L'annotation est utilisable sur des packages. Oui, vous avez bien entendu, des packages !

ElementType.TYPE

L'annotation pourra être utilisée sur une classe, une interface, une autre annotation, une énumération... Tout ce qui permet au langage de définir un type.

ElementType.ANNOTATION_TYPE

L'annotation sera utilisable sur d'autres annotations.

ElementType.METHOD

Vous l'avez deviné, ceci indique que l'annotation n'est utilisable que sur des méthodes...

ElementType.CONSTRUCTOR

Vous l'avez aussi deviné, l'annotation ne s'utilisera que sur des constructeurs !

ElementType.PARAMETER

Utilisable sur des paramètres de méthodes ou de constructeurs.

ElementType.FIELD

Utilisable sur des champs d'une classe.

ElementType.LOCAL_VARIABLE

L'annotation peut être utilisée sur une variable locale.

Nous ne pourrons donc mettre une annotation que sur un seul de ces types ?

Non. Cette méta-annotation accepte un tableau de types ce qui permet de définir plusieurs emplacements possibles pour une annotation.
Je vous propose de modifier nos annotations pour y ajouter ces contraintes :

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.SOURCE)
//Ici, nous spécifions un seul emplacement possible pour cette annotation
@Target(ElementType.METHOD)
public @interface AnnotationSource { }
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.CLASS)
//Grâce aux accolades, nous pouvons
//spécifier plusieurs emplacement possibles pour cette annotation
@Target({ElementType.TYPE, ElementType.FIELD})
public @interface AnnotationClass { }

Dès que vous avez modifié ces deux annotations, notre classe ClasseFille comporte maintenant une erreur et c'est normal car celle-ci a une annotation de méthode positionnée sur une classe. Si vous réexécutez le code précédent, vous devriez avoir une belle exception :

Image utilisateur

Pour corriger le problème, vous devez soit retirer l'annotation soit ajouter une méthode et y apposer l'annotation, comme ceci :

public class ClasseFille extends ClasseMere{ 
   @AnnotationSource
   public void doNothing(){}
}

Pour pouvoir l'utiliser, nous allons devoir modifier le paramètre de la méta-annotation @Retention dans l'annotation, ainsi :

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
//Ici, nous spécifions un seul emplacement possible pour cette annotation
@Target(ElementType.METHOD)
public @interface AnnotationSource { }

Et voici un code de test :

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class Test {
   public static void main(String[] args) {      
      
      //Nous pouvons récupérer les différentes annotations
      //grâce à la méthode getAnnotations() de l'objet Class
      System.out.println("Annotation utilisables pour la classe ClasseMere : "); 
      for(Annotation a : ClasseMere.class.getAnnotations())
         System.out.println("\t * " + a.annotationType());
      
      
      System.out.println("---------------------------------------------------");
      System.out.println("Annotation utilisables pour la classe ClasseFille : ");
      //Une autre manière de faire, avec une instance cette fois
      ClasseFille cFille = new ClasseFille();
      for(Annotation a : cFille.getClass().getAnnotations())
         System.out.println("\t * " + a.annotationType());
      
      //Nous récupérons la liste des méthodes définies
      Method[] methods = cFille.getClass().getDeclaredMethods();
      for(Method m : methods){
         //Pour chaque méthode, nous récupérons ses annotations
         Annotation[] annotations = m.getAnnotations();
         System.out.println("\nAnnotation sur la méthode " + m.toString() + " de la classe " + cFille.getClass().toString());
         for(Annotation a : annotations)
            System.out.println("\t -> " + a.annotationType());
      }
      
      
   }
}

Ce qui nous donne au final :

Annotation utilisables pour la classe ClasseMere : 
         * interface AnnotationZ
         * interface Temoin
---------------------------------------------------
Annotation utilisables pour la classe ClasseFille : 
         * interface AnnotationZ

Annotation sur la méthode public void ClasseFille.doNothing() de la classe class ClasseFille
         -> interface AnnotationSource

C'est relativement simple à comprendre. Par contre, pour annoter un package, c'est un peu particulier...

Utiliser une annotation @Target dans un package
  • Il vous faudra déjà avoir un package, normal. ^^

  • L'annotation devra être présente dans ce package.

  • Un fichier répondant au nom de package-info.java devra aussi être dans le package : celui-ci sert à informer la JVM que le package est annoté.

Je vous invite donc à créer un nouveau package, je l'ai nommé com.sdz.test et j'y ai mis deux annotations, une classe vierge, le fichier package-info.java et une classe de test, comme ceci :

Image utilisateur

Voici tous les codes sources de ces fichiers :

package com.sdz.annotation;
package com.sdz.test;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface PackageAnnotation { }
package com.sdz.test;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface PackageAnnotation2 { }
package com.sdz.test;

public class Test1 { }

Le fichier package-info.java ressemble à ceci :

@PackageAnnotation
@PackageAnnotation2
package com.sdz.test;

Il contient le nom du package précédé des annotations que nous souhaitons lui affecter.
Et maintenant, un code de test :

package com.sdz.test;

import java.lang.annotation.Annotation;

public class TestMain {
   public static void main(String[] args) {
      //nous pouvons récupérer le package à partir d'une classe
      Package pack = Test1.class.getPackage();
      System.out.println("Annotations utilisables pour le package : " + pack.getName());
      
      for(Annotation a : pack.getAnnotations())
         System.out.println("\t * " + a.annotationType());

   }
}

et son résultat :

Annotations utilisables pour le package : com.sdz.test
         * interface com.sdz.test.PackageAnnotation
         * interface com.sdz.test.PackageAnnotation2

Nous explorerons plus en détail les autres paramètres de cette méta-annotation dans un prochain chapitre mais, pour le moment, je vais vous présenter les annotations standards présentes dans le langage Java.

Les annotations standards

Les annotations standards sont des annotations marqueurs proposées par le langage Java. Elles sont au nombre de trois et ont toutes une utilisation bien précise.

@Deprecated

@Documented
@Retention(value=RUNTIME)
public @interface Deprecated

Cette annotation remplace le tag JavaDoc @deprecated en soulignant au compilateur que l'élément marqué ne devrait plus être utilisé. Si un tel élément est tout de même utilisé, Eclipse vous avertira en affichant un warning dans la vue qu'il vous met à disposition à cet effet.

Voici un exemple illustrant le comportement cette annotation :

@Deprecated
public class MaClasse { }
public class MaClasse2 {
   @Deprecated
   public void doSomething(){}
}
public class Main {

   public static void main(String[] args) {
        MaClasse mc = new MaClasse();
        MaClasse2 mc2 = new MaClasse2();
        mc2.doSomething();
   }
}

Et maintenant, voici comment Eclipse représente cette classe :

Image utilisateur

Vous pouvez voir que les instructions marquées sont rayées dans votre éditeur de code préféré et qu'un symbole (encadré en vert dans la capture) nous indique que le compilateur a relevé plusieurs warnings. Les voici :

Image utilisateur

Ce marqueur n'empêchera pas la compilation de votre code ni son fonctionnement mais il vous avertit sur le caractère obsolète d'un élément du langage ou de votre code.

Tu nous as dit que cette annotation remplaçait le tag JavaDoc @deprecated, mais je ne vois aucun commentaire sur la raison de la dépréciation...

C'est juste et, pour pallier à ce manque, je vous conseille d'utiliser conjointement le tag JavaDoc et l'annotation.

@SuppressWarnings

@Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(value=SOURCE)
public @interface SuppressWarnings

L'annotation @SuppressWarnings permet d'indiquer au compilateur que certains éléments du code ne doivent pas générer de warning lors de la compilation.
Elle prend en paramètre un tableau de String correspondant aux différents cas pouvant être gérés par cette annotation mais, car il y a un mais, les valeurs possibles ne sont pas standardisées et dépendent du compilateur utilisé.

Le compilateur Java et le compilateur qu'Eclipse utilise ne gèrent pas les mêmes valeurs pour cette annotation. Vu que nous ne travaillons pas en ligne de commande, je vous propose de passer en revue les valeurs tolérées par Eclipse.

Image utilisateur

Voici donc quelques valeurs tolérées par Eclipse pour cette annotation (pour la liste exhaustive, référez-vous à la documentation mentionnée ci-dessus) :

Valeur

Définition

all

Aucun warning ne sera remonté.

boxing

Contre les warnings relatifs au boxing ou l'unboxing.

cast

Pour supprimer les warnings sur des cast.

dep-ann

Evite les warning causés par une annotation dépréciée.

deprecation

Annule les warnings remontés par l'annotation @Deprecated.

fallthrough

En cas d'oubli d'une instruction break dans un bloc switch.

finally

Pour les warnings levés à cause d'un bloc finally douteux.

serial

Pour retirer le warning généré lorsque le champ serialVersionUID est manquant pour une classe serializable.

super

Supprime les warnings dans le cas d'une redéfinition de méthode sans invocation du mot clé super.

unused

Retire le warning sur un morceau de code inutilisé.

Je vous propose quelques exemples :

public class Main {
   
   public static void main(String[] args) {
      @SuppressWarnings("deprecation")
      MaClasse mc = new MaClasse();
      MaClasse2 mc2 = new MaClasse2();
      mc2.doSomething();        
   }
}

Retire le warning de dépréciation sur notre premier objet :

Image utilisateur

Ceci car nous avons apposé l'annotation directement sur la déclaration de notre objet, mais nous aurions pu annoter la méthode main() :

public class Main {

   @SuppressWarnings("deprecation")
   public static void main(String[] args) {
      MaClasse mc = new MaClasse();
      MaClasse2 mc2 = new MaClasse2();
      mc2.doSomething();        
   }
}

Ce qui retire tous les warnings de dépréciation :

Image utilisateur

Voici quelques autres cas, pour l'exemple :

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;


public class Main {

   //Nous pouvons passer un tableau de valeurs pour gérer plusieurs types de warnings d'un coup
   //pas de warning sur la dépréciation et l'utilisation de type non générique
   @SuppressWarnings({ "deprecation", "unchecked" })
   public static void main(String[] args) {
      //pas de warning sur les éléments non utilisés
      @SuppressWarnings("unused")
      MaClasse mc = new MaClasse();
      MaClasse2 mc2 = new MaClasse2();
      mc2.doSomething();
      //pas de warning sur les éléments non utilisés
      @SuppressWarnings("unused")
      int i = 1, j = 2;
      //Pas de warning sur un type générique utilisé sans typage
      @SuppressWarnings("rawtypes")
      List list = new ArrayList();
      list.add("toto");
      List<String> listString = new ArrayList<String>();
      listString.addAll(list);
   }
   
   //Pas de warning même si la méthode n'est pas utilisée
   @SuppressWarnings("unused")
   private static void doIt(int i){
         switch(i){
         case 1:
         case 2:
            System.out.println("coucou");
         case 3 :
      } 
   }
   
   @SuppressWarnings("serial")
   public class ExempleSerializable implements Serializable{
      //Plus de Warning en cas d'absence du serialUID
   }
}

Avec toutes ces annotations, rien dans l'onglet "Problems" d'Eclipse, mais si je les retire :

Que se passe-t-il si nous mettons une valeur erronée en paramètre ? Le programme plante ?

Non. Le compilateur ignorera tout simplement votre valeur. :magicien:
Une dernière chose avant de voir la dernière annotation standard : utilisez @SuppressWarnings avec parcimonie ! Certains warnings peuvent vous alerter sur les problèmes dans votre programme et il serait bon de voir s'il ne vaut pas mieux le corriger plutôt que l'ignorer...

Image utilisateur

@Override

@Target(value=METHOD)
@Retention(value=SOURCE)
public @interface Override

L'annotation @Override ne doit être utilisée que sur des méthodes redéfinies via le principe d'héritage. Elle informe le compilateur qu'une méthode est redéfinie et donc que celle-ci doit être présente dans la classe mère. Si cette annotation est utilisée sur une méthode non redéfinie, votre programme ne compilera pas. Voici un exemple simple qui fonctionne :

public class ExempleOverride {

   @Override
   public String toString() {
      return "ExempleOverride [getClass()=" + getClass() + ", hashCode()="
            + hashCode() + ", toString()=" + super.toString() + "]";
   }
}

Maintenant, si nous mettons une faute de frappe volontaire, comme ceci :

public class ExempleOverride {

   @Override
   public String toStrint() {
      return "ExempleOverride [getClass()=" + getClass() + ", hashCode()="
            + hashCode() + ", toString()=" + super.toString() + "]";
   }
}

Voici ce que nous dit Eclipse :

Image utilisateur

Maintenant que vous êtes familier avec les annotations, nous allons voir comment créer les vôtres.
Vous êtes toujours prêt ? Let's go!

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