web-dev-qa-db-fra.com

Comment différentes stratégies de rétention affectent-elles mes annotations?

Quelqu'un peut-il expliquer clairement les différences pratiques entre les Java.lang.annotation.RetentionPolicy constantes SOURCE, CLASS et RUNTIME?

De plus, je ne sais pas exactement ce que signifie "conserver l'annotation".

160
xdevel2000
  • RetentionPolicy.SOURCE: Jeter lors de la compilation. Ces annotations n'ont aucun sens une fois la compilation terminée, elles ne sont donc pas écrites dans le bytecode.
    Exemple: @Override, @SuppressWarnings

  • RetentionPolicy.CLASS: Jeter pendant le chargement de la classe. Utile lorsque vous effectuez un post-traitement au niveau du bytecode. Assez étonnamment, c'est le défaut.

  • RetentionPolicy.RUNTIME: Ne pas jeter. L'annotation doit être disponible pour la réflexion lors de l'exécution. Exemple: @Deprecated

Source: L'ancienne URL est morte maintenant hunter_meta et remplacé par hunter-meta-2-098036 . Au cas où même cela tomberait, je télécharge l'image de la page.

Image (Cliquez avec le bouton droit de la souris et sélectionnez 'Ouvrir l'image dans un nouvel onglet/une nouvelle fenêtre') Screenshot of Oracle website

192
Favonius

Selon vos commentaires sur la décompilation des classes, voici comment cela devrait fonctionner:

  • RetentionPolicy.SOURCE: N'apparaîtra pas dans la classe décompilée

  • RetentionPolicy.CLASS: Apparaît dans la classe décompilée, mais ne peut pas être inspecté au moment de l'exécution avec une réflexion avec getAnnotations()

  • RetentionPolicy.RUNTIME: Apparaît dans la classe décompilée et peut être inspecté à l'exécution avec une réflexion avec getAnnotations()

49
ewernli

Exemple minimal exécutable

Niveau de langue :

import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.SOURCE)
@interface RetentionSource {}

@Retention(RetentionPolicy.CLASS)
@interface RetentionClass {}

@Retention(RetentionPolicy.RUNTIME)
@interface RetentionRuntime {}

public static void main(String[] args) {
    @RetentionSource
    class B {}
    assert B.class.getAnnotations().length == 0;

    @RetentionClass
    class C {}
    assert C.class.getAnnotations().length == 0;

    @RetentionRuntime
    class D {}
    assert D.class.getAnnotations().length == 1;
}

Niveau de Bytecode : en utilisant javap, nous observons que la classe annotée Retention.CLASS Obtient un RuntimeInvisible attribut de classe:

#14 = Utf8               LRetentionClass;
[...]
RuntimeInvisibleAnnotations:
  0: #14()

tandis que l'annotation Retention.RUNTIME obtient un attribut de classe RuntimeVisible :

#14 = Utf8               LRetentionRuntime;
[...]
RuntimeVisibleAnnotations:
  0: #14()

et le Runtime.SOURCE annoté .class ne reçoit aucune annotation.

Exemples sur GitHub pour vous permettre de jouer.

RetentionPolicy.SOURCE: L'annotation serait disponible dans le code source du programme, ni dans le fichier .class, ni au moment de l'exécution. Utilisé par le compilateur.
RetentionPolicy.CLASS: L'annotation serait dans le fichier .class mais ne serait pas disponible au moment de l'exécution. Utilisé par des outils de manipulation de code octet tels que ASM, effectuer les modifications
RetentionPolicy.RUNTIME: L'annotation serait disponible au fichier .class et à l'exécution, pour inspection via Java réflexion via getAnnotations().

4
yoAlex5

Stratégie de rétention: une stratégie de rétention détermine à quel moment une annotation est supprimée.

1.SOURCE: annotation retained only in the source file and is discarded
          during compilation.
2.CLASS: annotation stored in the .class file during compilation,
         not available in the run time.
3.RUNTIME: annotation stored in the .class file and available in the run time.

Une stratégie de rétention est spécifiée à l'aide des annotations intégrées de Java: @Retention.

3
wahid_cse