Programmation Java/Annotations

Un livre de Wikilivres.

Un nouveau principe introduit par Java 5 est la gestion des méta-données grâce à un mécanisme appelé annotations.

Ces annotations sont ajoutées dans le code devant les classes et leurs membres (méthodes et champs) pour :

  • Ajouter des informations de documentation supplémentaires aux commentaires Javadoc[1],
  • Ajouter des contraintes de compilation (voir @Override par exemple),
  • Associer des méta-données qui peuvent être retrouvées par réflexion.

Malgré la similarité de syntaxe (arobase + nom) et de nom (@deprecated par exemple), il ne faut pas les confondre avec les tags Javadoc qui ne sont utilisés que par l'outil javadoc du JDK. De plus, une annotation correspond à un type de données (comme les classes, interfaces et énumérations). Ceci explique que la documentation d'un package possède une section supplémentaire nommée « Annotation Types » pour les annotations définies dans le package.

Toute entité (classe, interface, méthode ou champ) peut être précédée d'une ou plusieurs annotations contenant des méta-données renseignant le compilateur ou l'application elle-même. Ces annotations sont accessibles à l'exécution, en utilisant la réflexion, à partir de nouvelles méthodes de la classe java.lang.Class.

Syntaxe[modifier | modifier le wikicode]

La syntaxe d'une annotation est la suivante :

@annotation-type[ (name=value) * ]

La liste des paramètres entre parenthèses est optionnelle (vide par défaut). Elle contient une série de valeurs associées à un nom de champ définit par l'annotation.

Exemples[modifier | modifier le wikicode]

Exemple 1 :

@Author(
    name = "Moi",
    date = "02/01/2009"
)
class MyClass() { }

Exemple 2 :

@Override
void uneMethode() { }

Annotations existantes[modifier | modifier le wikicode]

Beaucoup d'annotations complètent les balises spéciales pour la documentation Javadoc.

@Deprecated[modifier | modifier le wikicode]

java.lang.Deprecated

Cette annotation marque une entité obsolète. Son utilisation génère un avertissement à la compilation, contrairement au tag @deprecated des commentaires Javadoc.

@Override[modifier | modifier le wikicode]

java.lang.Override

Cette annotation marque une méthode redéfinie.

Il ne s'agit pas d'une annotation de documentation mais d'un ajout de contrainte vérifiée à la compilation : une méthode marquée avec cette annotation doit obligatoirement être une méthode redéfinie de la classe mère. Dans le cas contraire (méthode non définie dans la classe mère), le compilateur génère une erreur annotation type not applicable to this kind of declaration.

À partir de Java 6, cette annotation peut aussi être utilisée pour les méthodes implémentant une interface.

@SuppressWarnings[modifier | modifier le wikicode]

java.lang.SuppressWarnings

Cette annotation signale au compilateur de supprimer certains avertissements à la compilation de l'entité.

Exemple 1 : pour supprimer les avertissements d'utilisations de méthodes obsolètes :

@SuppressWarnings("deprecation")
void uneMethode() { methodeObsolete(); }

Exemple 2 : pour supprimer les avertissements d'utilisations de méthodes obsolètes et d'utilisation de méthodes sans vérification de types (une version de la méthode avec types générique est préférable afin que le type d'élément soit vérifié) :

@SuppressWarnings({"unchecked", "deprecation"})
void uneMethode()
{
    Vector v=new Vector();
    methodeObsolete();
}

Créer de nouvelles annotations[modifier | modifier le wikicode]

La création est similaire à celle d'une interface.

Syntaxe[modifier | modifier le wikicode]

@interface identifiant
{
   type champ() [ default valeur ];
}

Exemple de définition:

@interface InfoClasse
{
    String auteur();
    int revision() default 1;
    String[] references();
}

Exemple d'utilisation:

@InfoClasse( auteur="Moi", references={"Reference1","Reference2"} )
class UneClasse { }

Cette nouvelle annotation peut elle-même être taguée avec des annotations du package java.lang.annotation indiquant l'utilisation qui en est faite.

Documentation pour Javadoc[modifier | modifier le wikicode]

Si l'annotation définit des informations à afficher dans la documentation générée par Javadoc, la définition de l'annotation doit utiliser l'annotation @Documented (java.lang.annotation.Documented).

Correction de l'exemple précédent :

@Documented
@interface InfoClasse
{
    String auteur();
    int revision() default 1;
    String[] references();
}

Informations disponibles à l'exécution[modifier | modifier le wikicode]

Pour que les informations d'une annotation soient disponibles à l'exécution, il faut annoter sa définition avec @Retention(RetentionPolicy.RUNTIME).

Exemple :

import java.lang.annotation.*; 

@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationPourExecution
{
   // Éléments d'information disponibles à l'exécution
}

Restreindre l'utilisation d'une annotation[modifier | modifier le wikicode]

La définition d'une annotation peut être annotée avec @Target pour spécifier avec quels types d'éléments l'annotation peut être utilisée.

La classe java.lang.annotation.ElementType définit les différents types qu'il est possible d'annoter.

Exemple :

import java.lang.annotation.*; 

@Target(ElementType.ANNOTATION_TYPE)
@interface PourAutreAnnotation
{
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@interface InfoMembreOuType
{
// Type = class/interface/enum
}

Accès aux annotations d'une classe[modifier | modifier le wikicode]

L'API de réflexion de Java permet d'accéder aux annotations d'une classe, méthode ou champ.

Exemple :

import java.lang.annotation.*; 

// ...

Class clas = objet.getClass(); // ou à partir d'une classe connue :   UneClasseConnue.class
Annotation[] annotations = clas.getAnnotations();

for (Annotation annotation : annotations)
{
    if (annotation instanceof InfoClasse)
    {
        InfoClasse infoClasse = (InfoClasse) annotation;
        System.out.println("auteur : " + infoClasse.auteur());
        System.out.println("revision : " + infoClasse.revision());
    }
}

Références[modifier | modifier le wikicode]