in

Comment décrire le code Java avec des annotations

Vous avez probablement rencontré des situations où vous avez besoin d'associer métadonnées (données décrivant d'autres données) avec des classes, des méthodes et/ou d'autres éléments d'application. Par exemple, votre équipe de programmation peut avoir besoin d'identifier des classes inachevées dans une application volumineuse. Pour chaque classe inachevée, les métadonnées incluraient probablement le nom du développeur responsable de la fin de la classe et la date d'achèvement prévue de la classe.

Avant Java 5, les commentaires étaient le seul mécanisme flexible que Java pouvait proposer pour associer des métadonnées à des éléments d'application. Cependant, les commentaires constituent un mauvais choix. Étant donné que le compilateur les ignore, les commentaires ne sont pas disponibles au moment de l'exécution. Et même s'ils l'étaient, le texte devrait être analysé pour obtenir des éléments de données cruciaux. Sans normalisation de la manière dont les éléments de données sont spécifiés, ces éléments de données pourraient s'avérer impossibles à analyser.

télécharger

Téléchargez le code source des exemples de ce didacticiel Java 101. Créé par Jeff Friesen pour InfoWorld.

Java 5 a tout changé en introduisant annotationsun mécanisme standard permettant d'associer des métadonnées à divers éléments d'application. Ce mécanisme se compose de quatre éléments :

  • Un @interface mécanisme de déclaration des types d'annotations.
  • Types de méta-annotations, que vous pouvez utiliser pour identifier les éléments d'application auxquels s'applique un type d'annotation ; pour identifier la durée de vie d'un annotation (une instance d'un type d'annotation) ; et plus encore.
  • Prise en charge du traitement des annotations via une extension de l'API Java Reflection (à discuter dans un prochain article), que vous pouvez utiliser pour découvrir les annotations d'exécution d'un programme, et un outil généralisé pour le traitement des annotations.
  • Types d'annotations standards.

J'expliquerai comment utiliser ces composants au fur et à mesure que nous progressons dans cet article.

Déclaration des types d'annotations avec @interface

Vous pouvez déclarer un type d’annotation en spécifiant le @ symbole immédiatement suivi du interface mot réservé et un identifiant. Par exemple, la liste 1 déclare un type d'annotation simple que vous pouvez utiliser pour annoter du code thread-safe.

Liste 1 : ThreadSafe.java

public @interface ThreadSafe
{
}

Après avoir déclaré ce type d'annotation, préfixez les méthodes que vous considérez comme thread-safe avec des instances de ce type en ajoutant @ immédiatement suivi du nom du type dans les en-têtes de méthode. Le listing 2 offre un exemple simple où le main() la méthode est annotée @ThreadSafe.

Liste 2 : AnnDemo.java (version 1)

public class AnnDemo
{
   @ThreadSafe
   public static void main(String() args)
   {
   }
}

ThreadSafe Les instances ne fournissent aucune métadonnée autre que le nom du type d'annotation. Cependant, vous pouvez fournir des métadonnées en ajoutant des éléments à ce type, où un élément est un en-tête de méthode placé dans le corps du type d'annotation.

En plus de ne pas avoir de corps de code, les éléments sont soumis aux restrictions suivantes :

  • L'en-tête de méthode ne peut pas déclarer de paramètres.
  • L'en-tête de méthode ne peut pas fournir de clause throws.
  • Le type de retour de l'en-tête de méthode doit être un type primitif (par exemple, int), java.lang.String, java.lang.Classune énumération, un type d'annotation ou un tableau de l'un de ces types. Aucun autre type ne peut être spécifié pour le type de retour.

À titre d’exemple, la liste 3 présente une ToDo type d'annotation avec trois éléments identifiant un travail de codage particulier, spécifiant la date à laquelle le travail doit être terminé et nommant le codeur responsable de l'achèvement du travail.

Liste 3 : ToDo.java (version 1)

public @interface ToDo
{
   int id();
   String finishDate();
   String coder() default "n/a";
}

Notez que chaque élément ne déclare aucun paramètre ou ne renvoie aucune clause et possède un type de retour légal (int ou String) et se termine par un point-virgule. De plus, l'élément final révèle qu'une valeur de retour par défaut peut être spécifiée ; cette valeur est renvoyée lorsqu'une annotation n'attribue pas de valeur à l'élément.

Liste de 4 utilisations ToDo pour annoter une méthode de classe inachevée.

Liste 4 : AnnDemo.java (version 2)

public class AnnDemo
{
   public static void main(String() args)
   {
      String() cities = { "New York", "Melbourne", "Beijing", "Moscow", 
                          "Paris", "London" };
      sort(cities);
   }

   @ToDo(id = 1000, finishDate = "10/10/2019", coder = "John Doe")
   static void sort(Object() objects)
   {
   }
}

La liste 4 attribue un élément de métadonnées à chaque élément ; par exemple, 1000 est affecté à id. Contrairement à coderle id et finishDate les éléments doivent être spécifiés ; sinon, le compilateur signalera une erreur. Lorsque coder aucune valeur n'est attribuée, elle assume sa valeur par défaut "n/a" valeur.

Java fournit une solution spéciale String value() élément qui peut être utilisé pour renvoyer une liste d'éléments de métadonnées séparés par des virgules. La liste 5 illustre cet élément dans une version refactorisée de ToDo.

Liste 5 : ToDo.java (version 2)

public @interface ToDo
{
   String value();
}

Quand value() est le seul élément d'un type d'annotation, vous n'avez pas besoin de le spécifier value et le = opérateur d'affectation lors de l'affectation d'une chaîne à cet élément. La liste 6 illustre les deux approches.

Liste 6 : AnnDemo.java (version 3)

public class AnnDemo
{
   public static void main(String() args)
   {
      String() cities = { "New York", "Melbourne", "Beijing", "Moscow", 
                          "Paris", "London" };
      sort(cities);
   }

   @ToDo(value = "1000,10/10/2019,John Doe")
   static void sort(Object() objects)
   {
   }

   @ToDo("1000,10/10/2019,John Doe")
   static boolean search(Object() objects, Object key)
   {
      return false;
   }
}

Utilisation des types de méta-annotations : le problème de la flexibilité

Vous pouvez annoter des types (par exemple, des classes), des méthodes, des variables locales, etc. Cependant, cette flexibilité peut être problématique. Par exemple, vous souhaiterez peut-être restreindre ToDo aux méthodes uniquement, mais rien n'empêche de l'utiliser pour annoter d'autres éléments d'application, comme le montre le Listing 7.

Liste 7 : AnnDemo.java (version 4)

@ToDo("1000,10/10/2019,John Doe")
public class AnnDemo
{
   public static void main(String() args)
   {
      @ToDo(value = "1000,10/10/2019,John Doe")
      String() cities = { "New York", "Melbourne", "Beijing", "Moscow", 
                          "Paris", "London" };
      sort(cities);
   }

   @ToDo(value = "1000,10/10/2019,John Doe")
   static void sort(Object() objects)
   {
   }

   @ToDo("1000,10/10/2019,John Doe")
   static boolean search(Object() objects, Object key)
   {
      return false;
   }
}

Dans la liste 7, ToDo est également utilisé pour annoter le AnnDemo classe et cities variable locale. La présence de ces annotations erronées peut dérouter quelqu'un qui examine votre code, ou même vos propres outils de traitement d'annotations. Pour les moments où vous devez réduire la flexibilité d'un type d'annotation, Java offre la Target type d'annotation dans son java.lang.annotation emballer.

Target est un type de méta-annotation — un type d'annotation dont les annotations annotent les types d'annotation, par opposition à un type d'annotation non méta dont les annotations annotent les éléments d'application, tels que les classes et les méthodes. Il identifie les types d'éléments d'application auxquels un type d'annotation est applicable. Ces éléments sont identifiés par Target's ElementValue() value() élément.

java.lang.annotation.ElementType est une énumération dont les constantes décrivent les éléments de l'application. Par exemple, CONSTRUCTOR s'applique aux constructeurs et PARAMETER s'applique aux paramètres. Liste 8 refactorisations Liste 5 ToDo type d'annotation pour le restreindre aux méthodes uniquement.

Liste 8 : ToDo.java (version 3)

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
public @interface ToDo
{
   String value();
}

Étant donné le refactorisé ToDo type d'annotation, une tentative de compilation du listing 7 génère désormais le message d'erreur suivant :

AnnDemo.java:1: error: annotation type not applicable to this kind of declaration
@ToDo("1000,10/10/2019,John Doe")
^
AnnDemo.java:6: error: annotation type not applicable to this kind of declaration
      @ToDo(value="1000,10/10/2019,John Doe")
      ^
2 errors

Types de méta-annotations supplémentaires

Java 5 a introduit trois types de méta-annotations supplémentaires, qui se trouvent dans le java.lang.annotation emballer:

  • Retention indique la durée de conservation des annotations avec le type annoté. Ce type est associé java.lang.annotation.RetentionPolicy enum déclare des constantes CLASS (le compilateur enregistre les annotations dans le fichier de classe ; la machine virtuelle ne les conserve pas pour économiser de la mémoire — politique par défaut), RUNTIME (le compilateur enregistre les annotations dans le fichier de classe ; la machine virtuelle les conserve), et SOURCE (le compilateur supprime les annotations).
  • Documented indique que les cas de Documented-les annotations annotées doivent être documentées par javadoc et des outils similaires.
  • Inherited indique qu'un type d'annotation est automatiquement hérité.

Java 8 a introduit le java.lang.annotation.Repeatable type de méta-annotation. Repeatable est utilisé pour indiquer que le type d'annotation dont il (méta-)annote la déclaration est répétable. En d'autres termes, vous pouvez appliquer plusieurs annotations du même type d'annotation répétable à un élément d'application, comme illustré ici :

@ToDo(value = "1000,10/10/2019,John Doe")
@ToDo(value = "1001,10/10/2019,Kate Doe")
static void sort(Object() objects)
{
}

Cet exemple suppose que ToDo a été annoté avec le Repeatable type d'annotation.

Traitement des annotations

Les annotations sont censées être traitées ; sinon, elles n'ont aucun intérêt. Java 5 a étendu l'API Reflection pour vous aider à créer vos propres outils de traitement d'annotations. Par exemple, Class déclare un Annotation()
getAnnotations()
méthode qui renvoie un tableau de java.lang.Annotation instances décrivant les annotations présentes sur l'élément décrit par le Class objet.

Le listing 9 présente une application simple qui charge un fichier de classe, interroge ses méthodes pour ToDo annotations et génère les composants de chaque annotation trouvée.

Liste 9 : AnnProcDemo.java

import java.lang.reflect.Method;

public class AnnProcDemo
{
   public static void main(String() args) throws Exception
   {
      if (args.length != 1)
      {
         System.err.println("usage: java AnnProcDemo classfile");
         return;
      }
      Method() methods = Class.forName(args(0)).getMethods();
      for (int i = 0; i < methods.length; i++)
      {
         if (methods(i).isAnnotationPresent(ToDo.class))
         {
            ToDo todo = methods(i).getAnnotation(ToDo.class);
            String() components = todo.value().split(",");
            System.out.printf("ID = %s%n", components(0));
            System.out.printf("Finish date = %s%n", components(1));
            System.out.printf("Coder = %s%n%n", components(2));
         }
      }
   }
}

Après avoir vérifié qu'un seul argument de ligne de commande (identifiant un fichier de classe) a été spécifié, main() charge le fichier de classe via Class.forName()invoque getMethods() pour renvoyer un tableau de java.lang.reflect.Method objets identifiant tous public méthodes dans le fichier de classe et traite ces méthodes.

Le traitement de la méthode commence par l'invocation Method's boolean isAnnotationPresent(Class extends
Annotation> annotationClass)
méthode pour déterminer si l'annotation décrite par ToDo.class est présent sur la méthode. Si c'est le cas, Method's T getAnnotation(Class
annotationClass)
la méthode est appelée pour obtenir l'annotation.

Le ToDo les annotations traitées sont celles dont les types déclarent un seul String value() élément (voir Listing 5). Étant donné que les métadonnées basées sur la chaîne de cet élément sont séparées par des virgules, elles doivent être divisées en un tableau de valeurs de composants. Chacune des trois valeurs de composants est ensuite consultée et générée.

Compilez ce code source (javac AnnProcDemo.java). Avant de pouvoir exécuter l'application, vous aurez besoin d'un fichier de classe approprié avec @ToDo annotations sur son public méthodes. Par exemple, vous pouvez modifier la liste 6 AnnDemo code source à inclure public dans son sort() et search() en-têtes de méthode. Vous aurez également besoin du Listing 10 ToDo type d'annotation, qui nécessite le RUNTIME politique de conservation.

Liste 10 : ToDo.java (version 4)

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

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ToDo
{
   String value();
}

Compiler le modifié AnnDemo.java et la liste 10, et exécutez la commande suivante pour traiter AnnDemo's ToDo annotations:

java AnnProcDemo AnnDemo

Si tout se passe bien, vous devriez observer le résultat suivant :

ID = 1000
Finish date = 10/10/2019
Coder = John Doe

ID = 1000
Finish date = 10/10/2019
Coder = John Doe

Types d'annotations standards

Avec Target, Retention, Documentedet InheritedJava 5 introduit java.lang.Deprecated, java.lang.Overrideet java.lang.SuppressWarningsCes trois types d'annotations sont conçus pour être utilisés uniquement dans un contexte de compilateur, c'est pourquoi leurs politiques de conservation sont définies sur SOURCE.

Obsolète

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

GIPHY App Key not set. Please check settings

    Côte d’Ivoire-AIP/ Des acteurs du système statistique national s’imprègnent des méthodes du calcul des indicateurs des ODD – AIP

    Un effondrement démographique mondial est-il en cours ?