N'affectent pas l'exécution du programme (en général), ajoutent de l'information au code ("meta data"). Servent au compilateur ou à différents outils (IDEs, déploiement).
Certaines annotations peuvent être examinées à l'exécution.
Java fournit 5 types prédéfinis (built-in) d'annotations.
Elles sont un type spécial d'interface, qui sont toutes (implicitement) des sous-interfaces de
java.lang.annotation.Annotation
.
Syntaxe à l'utilisation
Forme simple :// fait partie des annotations prédéfinies @Override void mySuperMethod() { ... }
// une annotation custom @EntityLe nom de l'annotation est la chaîne de caractère qui suit le
@
.
Certaines peuvent contenir des éléments, nommés ou pas :
@Author( name = "Benjamin Franklin", date = "3/27/2003" ) class MyClass() { ... }Si une annotation ne possède qu'un seul élément nommé
value
, il peut être omis :
@SuppressWarnings(value = "unchecked") void myMethod() { ... } // équivalent à : @SuppressWarnings("unchecked") void myMethod() { ... }Une déclaration peut utiliser plusieurs annotations :
@Author(name = "Jane Doe") @EBook class MyClass { ... }Plusieurs annotations du même type peuvent être utilisées dans la même déclaration :
@Author(name = "Jane Doe") @Author(name = "John Smith") class MyClass { ... }
Où les utiliser ?
Les annotations peuvent être appliquées aux déclarations de classe, champs et méthodes de classe et aux autres éléments d'un programme.Depuis java8, les annotations peuvent être utilisées lorsqu'on utilise un type, par exemple :
Création d'un objet
new @Interned MyObject();Type casting
myString = (@NonNull String) str;Clause
implements
class UnmodifiableListClauseimplements @Readonly List<@Readonly T> { ... }
throws
void monitorTemperature() throws @Critical TemperatureException { ... }
Annotations prédéfinies
Les 3 annotations de base dansjava.lang
sont @Deprecated
, @Override
, and @SuppressWarnings
.
@SafeVarargs
a été introduit dans java7 et @FunctionalInterface
dans java8.
@SuppressWarnings
Permet d'éviter des warnings à la compilation ; 2 types de warning :deprecation
et unchecked
.
@SuppressWarnings("deprecation") void useDeprecatedMethod() { objectOne.deprecatedMethod(); }Pour utiliser les 2, notation tableau :
@SuppressWarnings({"unchecked", "deprecation"})Une annotation non définie, par ex
@SuppressWarnings(“toto”)
, sera ignorée par le compilateur.
@Deprecated
(= déprécié, ne doit plus être utilisé).Doit être utilisé en lien avec javadoc (remarquer la différence de casse).
/** * @deprecated * Justification de la dépréciation */ @Deprecated static void deprecatedMethod() { } }
Exercice Deprecated
@Override
Pour signaler qu'un élément doit en surcharger un autre. Utilisé par exemple par un IDE pour signaler une typo, une erreur de type.Utile aussi pour être certain d'avoir bien la bonne signature dans notre code.
Note :
@Override
est à comprendre comme "overrides ou implements" (même sémantique que extends
pour les types génériques).
@Override int overriddenMethod() { }
@SafeVarargs
Utilisé lorsqu'on définit une méthode ou un constructeur avec des arguments variables de type générique.Permet de désactiver à la compilation des warnings relatifs à des vérifications de type sur les arguments variables de type générique.
Exercice SafeVarargs
@FunctionalInterface
Permet de signaler une interface dont l'implémentation peut être exprimée sous forme de lambda expression.Custom annotations
Pour utiliser des annotations personnalisées, il faut les définir.Les annotations sont un type spécial d'interface, qui sont toutes (implicitement) des sous-interfaces de
java.lang.annotation.Annotation
.
On utilise
@interface
pour définir une annotation, et on définit les éléments de l'annotation avec des méthodes, comme dans une interface normale.
@interface MyAnnotation { String value(); String name(); int age(); String[] newNames(); }Par rapport à une interface normale :
- Elle ne peuvent pas être génériques.
- Elles ne peuvent pas dériver d'une autre interface que
Annotation
. - Leurs méthodes ne peuvent pas avoir de paramètres.
- Elles ne peuvent pas définir de méthodes qui lancent des exceptions.
- Les types de retour de leurs méthodes peuvent être des types primitifs, des tableaux mais pas des objets complexes.
- Les méthodes peuvent avoir des types de retour.
@interface ClassHeader { String author(); String date(); int currentRevision() default 1; String lastModified() default "N/A"; String lastModifiedBy() default "N/A"; String[] reviewers(); // tableau }Et à l'utilisation :
@ClassHeader ( author = "John Doe", date = "3/17/2002", currentRevision = 6, lastModified = "4/12/2004", lastModifiedBy = "Jane Doe", reviewers = {"Alice", "Bob", "Cindy"} // notation tableau ) public class MyClass { ... }
Exercice EnhancementRequest
Meta-annotations (ou annotations d'annotations)
Permettent d'annoter la définition des annotations, pour spécifier où le nouveau type d'annotation peut être utilisé et comment il sera utilisé à la compilation et à l'exécution.Par exemple, si on veut que les annotations soient utilisées par javadoc, il faut annoter la déclaration de l'annotation ("meta-annotation") avec
@Documented
:
import java.lang.annotation.*; // pour utiliser @Documented @Documented @interface ClassHeader { ... }Les meta-annotations possibles sont :
@Target @Retention @Documented @Inherited @Repeatable
@Target
Permet de spécifier où la nouvelle annotation peut être utilisée.Peut prendre les valeurs de l'enum
java.lang.annotation.ElementType
:
TYPE FIELD METHOD PARAMETER CONSTRUCTOR LOCAL_VARIABLE ANNOTATION_TYPE PACKAGE TYPE_PARAMETER TYPE_USEPar exemple pour indiquer qu'une annotation ne peut s'appliquer qu'aux méthodes :
import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target({ElementType.METHOD}) public @interface MyAnnotation { String value(); }
@Retention
Permet d'indiquer au compilateur et à l'interpréteur à quel endroit les annotations doivent être disponibles.Peuvent prendre les valeurs de l'enum
java.lang.annotation.RetentionPolicy
:
-
SOURCE
: tout simplement ignorées par le compilateur (sert à documenter le code, donc utile aux gens qui lisent le code). -
CLASS
: rarement utilisé ; présent dans le .class mais pas accessible à l'exécution -
RUNTIME
: accessible à l'exécution (par reflection).
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Nickname { String[] value() default {}; }
@Inherited
Indique si les sous-classes d'une classe annotée héritent de l'annotationimport java.lang.annotation.Inherited @Inherited public @interface MyAnnotation { } @MyAnnotation public class MySuperClass { ... } public class MySubClass extends MySuperClass { ... }
MySubClass
hérite de l'annotation.
@Documented
Indique si l'annotation sera visible dans le javadoc.Par exemple, le code source de
java.lang.FunctionalInterface
:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface {}
Autres annotations
Java fournit un nombre réduit d'annotations dansjava.lang
et java.lang.annotation
, mais les annotations personnalisées permettent d'en ajouter selon les besoin, ce qui est fait dans certains packages de l'API (liste complète dans la doc de java.lang.annotation.Annotation
).
Il est possible aussi d'inclure dans son code des annotations définies dans des libs ("pluggable annotation type system").
Par exemple, on peut vouloir sécuriser son code contre des
NullPointerException
, définir une annotation @NonNull
, et obtenir un warning à la compilation sur une instruction du type
@NonNull String str;
Exercice
Installer et faire marcher checkerframework.org
Vous pouvez vous aider du code de test qui se trouve dans l'exemple checkerframework.org.
Le fichier README contient l'instruction
Les jars nécessaires sont dans le répertoire bin/checkerframework.org/
Par curiosité, vous pouvez aller voir le code implémentant le null checker sur github.
Vous pouvez vous aider du code de test qui se trouve dans l'exemple checkerframework.org.
Le fichier README contient l'instruction
javac
pour compiler.
Les jars nécessaires sont dans le répertoire bin/checkerframework.org/
Par curiosité, vous pouvez aller voir le code implémentant le null checker sur github.