Modification des paramètres d'annotation à l'exécution

1. Vue d'ensemble

Annotations , une forme de métadonnées que vous pouvez ajouter au code Java. Ces annotations peuvent être traitées au moment de la compilation et incorporées aux fichiers de classe ou peuvent être conservées et accessibles au moment de l'exécution à l'aide de Reflection .

Dans cet article, nous expliquerons comment modifier la valeur d' annotation au moment de l'exécution à l'aide de Reflection . Nous utiliserons l'annotation au niveau de la classe pour cet exemple.

2. Annotation

Java permet de créer de nouvelles annotations en utilisant celles existantes. Dans la forme la plus simple, une annotation est représentée par le symbole @ suivi du nom de l'annotation:

@Override

Créons notre propre Greeter d' annotation :

@Retention(RetentionPolicy.RUNTIME) public @interface Greeter { public String greet() default ""; }

Maintenant, nous allons créer une classe Java Greetings qui utilise l' annotation au niveau de la classe :

@Greeter(greet="Good morning") public class Greetings {} 

Maintenant, nous allons accéder à la valeur d'annotation en utilisant la réflexion. La classe Java Class fournit une méthode getAnnotation pour accéder aux annotations d'une classe:

Greeter greetings = Greetings.class.getAnnotation(Greeter.class); System.out.println("Hello there, " + greetings.greet() + " !!");

3. Modifier l'annotation

Classe Java La classe maintient une carte pour la gestion des annotations - Classe d' annotation en tant que clés et objet Annotation en tant que valeur:

Map
    
      map;
    

Nous mettrons à jour cette carte pour modifier l'annotation au moment de l'exécution. L'approche pour accéder à cette carte diffère selon les différentes implémentations JDK. Nous en discuterons pour JDK7 et JDK8.

3.1. Implémentation JDK 7

Classe Java La classe a des annotations de champ . Comme il s'agit d'un champ privé, pour y accéder, nous devons définir l'accessibilité du champ sur true . Java fournit la méthode getDeclaredField pour accéder à n'importe quel champ par son nom:

Field annotations = Class.class.getDeclaredField(ANNOTATIONS); annotations.setAccessible(true); 

Maintenant, accédons à la carte d'annotation pour la classe Greeter :

 Map
    
      map = annotations.get(targetClass);
    

Maintenant, c'est la carte qui contient des informations sur toutes les annotations et leur objet de valeur. Nous voulons modifier la valeur d'annotation Greeter que nous pouvons obtenir en mettant à jour l'objet d'annotation de la classe Greeter :

map.put(targetAnnotation, targetValue);

3.2. Implémentation JDK 8

Les implémentations de Java 8 stockent les informations d' annotations dans une classe AnnotationData . Nous pouvons accéder à cet objet en utilisant la méthode annotationData . Nous allons définir l'accessibilité de la méthode annotationData sur true car il s'agit d'une méthode privée:

Method method = Class.class.getDeclaredMethod(ANNOTATION_METHOD, null); method.setAccessible(true);

Maintenant, nous pouvons accéder au champ d' annotations . Comme ce champ est également un champ privé, nous définirons l'accessibilité sur true :

Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS); annotations.setAccessible(true);

Ce champ a une carte de cache d'annotations qui stocke la classe d'annotation et l'objet de valeur. Modifions cela:

Map
    
      map = annotations.get(annotationData); map.put(targetAnnotation, targetValue);
    

4. Application

Prenons cet exemple:

Greeter greetings = Greetings.class.getAnnotation(Greeter.class); System.err.println("Hello there, " + greetings.greet() + " !!");

Ce sera une salutation «Bonjour» car c'est la valeur que nous avons fournie à l'annotation.

Maintenant, nous allons créer un autre objet de type Greeter avec la valeur "Bonsoir":

Greeter targetValue = new DynamicGreeter("Good evening"); 

Mettons à jour la carte d'annotation avec la nouvelle valeur:

alterAnnotationValueJDK8(Greetings.class, Greeter.class, targetValue);

Vérifions à nouveau la valeur du message d'accueil:

greetings = Greetings.class.getAnnotation(Greeter.class); System.err.println("Hello there, " + greetings.greet() + " !!");

Il accueillera comme «Bonsoir».

5. Conclusion

Les implémentations Java utilisent deux champs de données pour stocker les données d' annotation : les annotations , les annotations déclarées . La différence entre ces deux: d'abord stocker les annotations des classes parentes également et plus tard, on ne stocke que pour la classe actuelle.

Comme l'implémentation de getAnnotation diffère dans JDK 7 et JDK 8, nous utilisons ici la carte des champs d' annotations pour plus de simplicité.

Et, comme toujours, le code source de l'implémentation est disponible sur Github.