Modification des paramètres d’annotation au moment de l’exécution

Modification des paramètres d'annotation au moment de l'exécution

1. Vue d'ensemble

Annotations, une forme de métadonnées que vous pouvez ajouter au code Java. Ces analysesannotations ont 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 deReflection.

Dans cet article, nous verrons comment modifier la valeur deannotation au moment de l'exécution à l'aide deReflection. Nous allons utiliser une annotation au niveau classe pour cet exemple.

2. Annotation

Java permet de créer de nouveauxannotations en utilisant ceux existants. 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 annotationGreeter:

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

Maintenant, nous allons créer une classe JavaGreetings qui utilise le niveau de classeannotation:

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

Maintenant, nous allons accéder à la valeur d'annotation en utilisant la réflexion. La classe JavaClass fournit une méthodegetAnnotation 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

La classe JavaClass contient une carte pour gérer les annotations - la classeAnnotation en tant que clés et l'objetAnnotation en tant que valeur:

Map, Annotation> map;

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

3.1. Implémentation JDK 7

Classe JavaClass has champannotations. Comme il s'agit d'un champ privé, pour y accéder, nous devons définir l'accessibilité du champ àtrue. Java fournit la méthodegetDeclaredField 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'annotations pour la classeGreeter:

 Map, Annotation> map = annotations.get(targetClass);

Il s’agit maintenant de la carte qui contient des informations sur toutes les annotations et leur objet de valeur. Nous voulons modifier la valeur d'annotation deGreeter que nous pouvons obtenir en mettant à jour l'objet d'annotation de la classeGreeter:

map.put(targetAnnotation, targetValue);

3.2. Implémentation JDK 8

Les implémentations Java 8 stockent les informations deannotations dans une classeAnnotationData. Nous pouvons accéder à cet objet en utilisant la méthodeannotationData. Nous définirons l'accessibilité pour la méthodeannotationData surtrue 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 champannotations. Comme ce champ est également un champ privé, nous définirons l'accessibilité àtrue:

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

Ce champ contient une carte de cache des annotations qui stocke une classe d'annotation et un objet de valeur. Changeons cela:

Map, Annotation> 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 un bonjour, car c’est la valeur que nous avons fournie aux annotations. Maintenant, nous allons créer un autre objet de typeGreeter 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 sera salué comme "bonsoir".

5. Conclusion

Les implémentations Java utilisent deux champs de données pour stocker les données d'annotation:annotations,declaredAnnotations. La différence entre ces deux: les annotations de premier magasin des classes parentes également et les magasins suivants uniquement pour la classe actuelle.

Comme l'implémentation degetAnnotation diffère dans JDK 7 et JDK 8, nous utilisons iciannotations field map pour plus de simplicité.

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