Ändern von Anmerkungsparametern zur Laufzeit

1. Übersicht

Anmerkungen , eine Form von Metadaten, die Sie dem Java-Code hinzufügen können. Diese Anmerkungen können zur Kompilierungszeit verarbeitet und in Klassendateien eingebettet werden oder können zur Laufzeit mithilfe von Reflection beibehalten und aufgerufen werden .

In diesem Artikel wird erläutert, wie Sie den Anmerkungswert zur Laufzeit mithilfe von Reflection ändern . In diesem Beispiel werden Annotationen auf Klassenebene verwendet.

2. Anmerkung

Java ermöglicht das Erstellen neuer Anmerkungen unter Verwendung vorhandener. In der einfachsten Form wird eine Anmerkung als @ -Symbol dargestellt, gefolgt vom Namen der Anmerkung:

@Override

Lassen Sie uns unsere eigene Anmerkung erstellen. Greeter :

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

Jetzt erstellen wir eine Java-Klasse Greetings, die die Annotation auf Klassenebene verwendet :

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

Jetzt greifen wir mithilfe von Reflection auf den Anmerkungswert zu. Die Java-Klasse Class bietet eine Methode getAnnotation, um auf Anmerkungen einer Klasse zuzugreifen:

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

3. Anmerkung ändern

Java - Klasse Klasse hält eine Karte für die Verwaltung von Annotationen - Annotation - Klasse als Schlüssel und Annotation - Objekt als Wert:

Map
    
      map;
    

Wir werden diese Map aktualisieren, um die Annotation zur Laufzeit zu ändern. Der Ansatz für den Zugriff auf diese Karte unterscheidet sich in verschiedenen JDK-Implementierungen. Wir werden es für JDK7 und JDK8 diskutieren.

3.1. JDK 7-Implementierung

Die Java-Klasse Class verfügt über Feldanmerkungen . Da dies ein privates Feld ist, müssen wir die Zugänglichkeit des Feldes auf true setzen, um darauf zugreifen zu können . Java bietet die Methode getDeclaredField, um auf jedes Feld mit seinem Namen zuzugreifen:

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

Lassen Sie uns nun auf die Anmerkungskarte für die Klasse Greeter zugreifen :

 Map
    
      map = annotations.get(targetClass);
    

Dies ist nun die Karte, die Informationen zu allen Anmerkungen und ihrem Wertobjekt enthält. Wir möchten den Greeter- Annotationswert ändern , den wir durch Aktualisieren des Annotationsobjekts der Greeter- Klasse erreichen können:

map.put(targetAnnotation, targetValue);

3.2. JDK 8-Implementierung

Java 8-Implementierungen speichern Anmerkungsinformationen in einer Klasse AnnotationData . Wir können mit der annotationData- Methode auf dieses Objekt zugreifen . Wir setzen die Barrierefreiheit für die annotationData- Methode auf true, da es sich um eine private Methode handelt:

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

Jetzt können wir auf das Feld für Anmerkungen zugreifen . Da dieses Feld auch ein privates Feld ist, setzen wir die Barrierefreiheit auf true :

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

Dieses Feld enthält eine Annotations-Cache-Zuordnung, in der die Annotationsklasse und das Wertobjekt gespeichert sind. Lassen Sie uns das ändern:

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

4. Anwendung

Nehmen wir dieses Beispiel:

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

Dies ist die Begrüßung von „Guten Morgen“, da dies der Wert ist, den wir für die Anmerkung angegeben haben.

Jetzt erstellen wir ein weiteres Objekt vom Typ Greeter mit dem Wert "Guten Abend":

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

Lassen Sie uns die Annotation Map mit dem neuen Wert aktualisieren:

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

Lassen Sie uns den Begrüßungswert noch einmal überprüfen:

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

Es wird als "Guten Abend" begrüßt.

5. Schlussfolgerung

Java-Implementierungen verwenden zwei Datenfelder zum Speichern von Anmerkungsdaten: Anmerkungen , deklarierte Anmerkungen . Der Unterschied zwischen diesen beiden: Zuerst werden Anmerkungen von übergeordneten Klassen gespeichert, und später werden nur Anmerkungen für die aktuelle Klasse gespeichert.

Da sich die Implementierung von getAnnotation in JDK 7 und JDK 8 unterscheidet, verwenden wir hier der Einfachheit halber die Feldkarte für Anmerkungen .

Und wie immer ist der Quellcode der Implementierung auf Github verfügbar.