From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100277.html | 712 +++++++++++++++++++++ 1 file changed, 712 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100277.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100277.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100277.html b/Master/Reference Architectures and Patterns/hjp5/html/k100277.html new file mode 100644 index 0000000..7140acc --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100277.html @@ -0,0 +1,712 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 43 - Reflection +
+
+ + + + +

43.6 Annotationen oder Metainformationen +im Javacode

+
+ +
+ + + + +

43.6.1 Metainformationen

+ +

+Was sind eigentlich Metainformationen und wofür sind sie gut? +Nun, Metainformationen sind einfach Informationen über Informationen +und können dafür verwendet werden, zusätzliches Wissen +abzulegen. In unserem Fall handelt es sich dabei um zusätzliches +Wissen über Javaprogramme, das zusammen mit dem Quellcode abgelegt +werden kann, die Arbeitsweise eines Programms jedoch nicht beeinflusst. + +

+An verschiedenen Stellen sind wir sogar schon mit Annotationen in +Berührung gekommen. So sind beispielsweise die zusätzlichen +Tags @param +oder @return +für das JavaDoc-Werkzeug, (steht in Abschnitt 51.5.3) +nichts anderes als zusätzliche Informationen, die dazu verwendet +werden können, die Schnittstellen eines Programms besser zu dokumentieren. + +

+Im Kapitel über Persistenz werden wir außerdem sehen, dass +Annotationen häufig dazu verwendet werden, Konfigurationsinformationen +für zusätzlichen Frameworks zusammen mit dem betreffenden +Code abzulegen und uns so weitestgehend von der Last zusätzlicher +Konfigurationsdateien zu befreien. Es ist jedoch ebenso leicht eigene +Annotationen zu entwickeln und ihre Informationen anschließend +über das Reflection API auswerten. Wir werden dies anhand einer +eigenen Annotation demonstrieren, die es gestattet, Revisionsinformationen +im Quellcode zu hinterlegen. Diese geben Auskunft darüber , wann +und von wem eine Klasse oder eine Methode zuletzt verändert worden +sind. + + + + +

43.6.2 Eine einfache Annotation

+ +

+Bevor wir die Revisionsinformationen in unsere Klassen integrieren +und über die Reflection API auswerten können, müssen +wir sie zunächst definieren. + + + + +

Die Annotationsklasse

+ +

+Mit Annotationen verhält es sich ähnlich wie mit einem Interface, +das in gewisser Weise auch zusätzliche Informationen über +eine Klasse zur Verfügung stellt. So ist es kaum verwunderlich, +dass eine Annotation ganz ähnlich definiert wird: + + +

+ + + + +
+ +
+001 /**
+002  * Eine einfache Annotation
+003  */
+004 public @interface Revision
+005 {
+006 }
+
+
+ +Listing 43.10: Eine einfache Annotation

+ +

+Bis auf das vorangestellte @-Zeichen +unterscheidet sich die Definition einer Annotation also nicht von +der eines normalen Interfaces, wie es in Kapitel 9 +beschrieben wird. Im Gegensatz zu reinen Interfaces kann eine Annotation +allerdings nicht nur für Klassen verwendet werden. + + + + +

Verwendung von Annotationen

+ +

+Annotationen dienen dazu, zusätzliche Informationen im Quellcode +zu hinterlegen. Dabei können folgende Elemente annotiert werden: +

+ +

+Da nicht alle Annotationen bei allen Elementen Sinn machen, werden +wir später sehen, wie wir diese Liste einschränken können. +Um nun beispielsweise die in Abschnitt 43.4 +beschriebene Klasse PrintableObject +und die von dieser definierte Methode toString +mit Zusatzinformationen zu versehen schreiben wir ihren Namen dieser +einfach vor die Liste der vorhandenen Modifier: + + +

+ + + + +
+ +
+001 import java.lang.reflect.*;
+002 
+003 @Revision public class PrintableObject
+004 {
+005   @Revision public String toString()
+006   {
+007   ...
+008   }
+009 }
+
+
+ +Listing 43.11: Verwendung der Annotation

+ +

+Geschafft! Sie können Ihre Annotationen nun genau wie die anderen +Modifier verwenden und einfach vor das zu annotierende Element schreiben. +Schon ist der Code mit den gewünschten Zusatzinformationen angereichert. + +

+Der eine oder andere Leser könnte jetzt anmerken, dass die Klasse +zwar nun annotiert ist, jedoch noch keine wirklichen Zusatzinformationen +enthält. Zwar sind ist die Klasse PrintableObject +und die Methode toString annotiert, +allerdings wissen wir nicht vom wem und wann. Diese Informationen +werden wir nun ergänzen. + + + + +

43.6.3 Annotationen mit einem Wert

+ +

+Um tatsächlich zusätzliche Informationen ablegen zu können, +müssen wir die Annotation nun gewissermaßen mit einer Variablen +ausstatten. Dazu erweitern wir die Definition wie folgt: + + +

+ + + + +
+ +
+001 /**
+002  * Eine Annotation mit einer Variablen
+003  */
+004 public @interface Revision
+005 {
+006   String value();
+007 }
+
+
+ +Listing 43.12: Annotation mit einer Variablen

+ +

+Die Annotation besitzt nun die Variable value, +die die eigentliche Information aufnehmen kann und im Gegenzug auch +belegt werden muss. Der Wert der Variablen value +wird bei der Verwendung der Annotation in der Klasse PrintableObject +gesetzt. + + +

+ + + + +
+ +
+001 import java.lang.reflect.*;
+002 
+003 @Revision("Wurde zuerst geändert")
+004 public class PrintableObject
+005 {
+006   @Revision("Wurde anschließend geändert")
+007   public String toString()
+008   {
+009   ...
+010   }
+011 }
+
+
+ +Listing 43.13: Zuweisen von annotierten Werten

+ +

+Die Annotationen sind zwar nun jeweils eine Zeile nach oben gerückt, +aber für den Compiler steht sie immer noch in der Liest der Modifier. +Wir können Javaklassen prinzipiell auch als Einzeiler formulieren. +Um die Übersicht zu wahren, ist es aber von Vorteil, lange Annotationen +in eine separate Zeile zu stellen. + +

+Wie Sie sehen, sind nun beide Annotationen mit unterschiedlichen Werten +ausgestattet, die wir später auch auswerten können. + + + + +

43.6.4 Beliebige Schlüssel-Wert-Paare in Annotationen

+ +

+Das Element value, welches in +den vorangegangenen Listings den Wert aufnimmt ist zwar praktisch, +aber um detailliertere Informationen ablegen zu können, müssten +wir nun weitere Annotationen definieren, was in einem Wust von zusätzlichen +»Modifizierern« enden würde. Um dies zu vermeiden und +zusammengehörende Informationen in einer Annotation zusammenzufassen, +können diese beliebig viele Informationen aufnehmen. + +

+Der Schlüssel value stellt +dabei nur einen Spezialfall für ein Standard-Attribut dar. Wenn +wir den Namen des Attributs nicht angeben weißt Java den Wert +der Annotation dem Attribut value +zu. Alternativ wäre auch folgende Schreibweise möglich gewesen: + + +

+ + + + +
+ +
+001 import java.lang.reflect.*;
+002 
+003 @Revision(value = "Wurde zuerst geändert")
+004 public class PrintableObject
+005 {
+006   @Revision(value = "Wurde anschließend geändert")
+007   public String toString()
+008   {
+009   ...
+010   }
+011 }
+
+
+ +Listing 43.14: Zuweisen von annotierten Werten

+ +

+Nachdem wir die einzelnen Attribute einer Annotation nun genau adressieren +können, verfeinern wir diese folgendermaßen: + + +

+ + + + +
+ +
+001 /**
+002  * Annotation mit mehreren Variablen
+003  */
+004 public @interface Revision
+005 {
+006   int id();
+007   String name();
+008   String vorname();
+009   String notizen();
+010 }
+
+
+ +Listing 43.15: Komplexe Annotation

+ +

+Das unspezifische Attribut value +ist nun ein Reihe von detaillierten Einzelattributen gewichen, die +natürlich auch gefüllt werden möchten: + + +

+ + + + +
+ +
+001 import java.lang.reflect.*;
+002 
+003 @Revision( id = 1, name = "Krüger", vorname = "Guido", 
+004            notizen = "Klasse erstellt")
+005 public class PrintableObject
+006 {
+007   @Revision( id = 2, name = "Stark", vorname = "Thomas", 
+008 	           notizen = "Methode hinzugefügt")
+009   public String toString()
+010   {
+011   ...
+012   }
+013 }
+
+
+ +Listing 43.16: Zuweisen von annotierten Werten

+ +

+Dies sieht doch schon nach brauchbaren Informationen aus und bringt +uns zu der Frage, welche Datentypen Annotations-Attribute besitzen +dürfen. + + + + +

Unterstützte Datentypen

+ +

+Die Attribute einer Annotation dürfen folgende Typen besitzen: +

+ +

+Die Liste ist auf diese Typen beschränkt, weil der Compiler mit +ihnen die nötigen Typüberprüfungen vornehmen kann. + + + + +

43.6.5 Standardwerte für Attribute

+ +

+Die Spezifikation für Annotation schreibt vor, dass alle definierten +Attribute einer Annotation auch verwendet werden müssen. Um dennoch +optionale Attribute definieren zu können, gestattet es die Spezifikation, +Standardwerte festzulegen. Wir demonstrieren dies, indem wir die Notizen +der Annotationen nun mit einem leeren String +vorbelegen. + + +

+ + + + +
+ +
+001 /**
+002  * Annotation mit mehreren Variablen
+003  */
+004 public @interface Revision
+005 {
+006   int id();
+007   String name();
+008   String vorname();
+009   String notizen() default "";
+010 }
+
+
+ +Listing 43.17: Komplexe Annotation

+ +

+Nun ist die Angabe des Attributes notizen +bei der Verwendung von Annotationen optional, da der Wert bereits +vorinitialisiert ist. Gegebenenfalls wird der Default-Wert natürlich +mit dem jeweils Angegebenen überschrieben. + + + + +

43.6.6 Einschränken von Annotationen

+ +

+Bisher haben wir noch keinerlei Einschränkungen für unsere +Annotation definiert und können diese deshalb sowohl für +Pakete wie auch für lokale Variablen verwenden. Da jedoch nicht +jede Annotation für jedes Element sinnvoll ist, können wir +ihre Verwendung bei Bedarf einschränken. Und warum sollten wir +hierfür etwas anderes verwenden als wiederum eine Annotation. + + + + +

Einschränken der Verwendbarkeit

+ +

+Über die Annotation @Target +können wir die Verwendbarkeit einer Annotationen auf bestimmte +Elemente einschränken. Mögliche Werte sind: +

+ +

+Da wir uns am Anfang des Kapitels entschlossen haben die Annotation +auf Klassen und Methoden zu beschränken, ergänzen wir das +Listing der Revision ein weiteres +Mal: + + +

+ + + + +
+ +
+001 import java.lang.annotation.Target;
+002 import java.lang.annotation.ElementType;
+003 
+004 // Diese Annotation ist auf Klassen und Methoden beschränkt
+005 @Target({ElementType.TYPE, ElementType.METHOD})
+006 public @interface Revision
+007 {
+008   int id();
+009   String name();
+010   String vorname();
+011   String notizen() default "";
+012 }
+
+
+
+ +Listing 43.18: Einschränken der Verwendbarkeit

+ +

+An diesem Beispiel können Sie außerdem die Verwendung von +Arrays und Aufzählungen (Enum) als Attribut der Annotation Target +nachvollziehen. Die Variable value +dieser Annotation enthält ein Array aus Aufzählungsobjekten, +deren Werte in einer geschweifen Klammer und durch Kommata getrennt +definiert werden. Wenn Sie das Target +nicht spezifizieren, kann die Annotation universell verwendet werden. + + + + +

Einschränken der Sichtbarkeit

+ +

+Die Verwendungsmöglichkeiten von Annotationen reichen von Zusatzinformationen +für Dokumentationstools bis hin zu Konfigurationsdaten, die das +Laufzeitverhalten der Java Virtual Machine beeinflussen können. +Um nicht alle - möglicherweise - unnötigen Metainformationen +bereitstellen zu müssen, lassen sich diese über die Annotation +@Retention +in 3 Kategorien einteilen: + +

+ + + + + + + + + + + + + + +
Attribut Verwendung
SOURCE +Diese Informationen sind nur Bestandteil +der Sourcedatei und werden nicht in die Klassen einkompiliert
CLASS +Diese Informationen werden vom Compiler +in die Classdatei integriert, stehen aber nicht zur Laufzeit zur Verfügung
RUNTIME +Diese Informationen werden vom Compiler +in die Classdatei integriert und können zur Laufzeit über +das Reflection API ausgelesen werden
+

+Tabelle 43.2: Sicherbarkeitsattribute

+ +

+Wenn Sie keine Angabe zur Retention machen, +wird die RetentionPolicy +CLASS als Standardwert ausgewählt. +Da unsere Annotation jedoch auch zur Laufzeit zur Verfügung stehen +soll, erweitern wir das Listing ein letztes Mal: + + +

+ + + + + +
+ +
+001 import java.lang.annotation.Target;
+002 import java.lang.annotation.ElementType;
+003 import java.lang.annotation.Retention;
+004 import java.lang.annotation.RetentionPolicy;
+005 
+006 // Diese Annotation ist auf Klassen und Methoden beschränkt
+007 @Target({ElementType.TYPE, ElementType.METHOD})
+008 
+009 // Die Information soll auch zur Laufzeit zur Verfügung stehen
+010 @Retention(RetentionPolicy.RUNTIME)
+011 public @interface Revision
+012 {
+013   int id();
+014   String name();
+015   String vorname();
+016   String notizen() default "";
+017 }
+
+
+Revision.java
+ +Listing 43.19: Vollständige Annotation

+ + + + +

Dokumentieren der Annotation und Vererbung

+ +

+Über die zusätzliche Annotation @Documented +kann schließlich gesteuert werden, ob die Verwendung der Annotation +auch in der JavaDoc-Dokumentation angezeigt werden soll. Und über +die Annotation @Inherited +gibt man an, ob eine annotierte Klasse diese Zusatzinformationen auch +an davon abgeleitete Klassen vererbt. + + + + +

43.6.7 Auslesen von Annotationen

+ +

+Da dies primär ein Kapitel über Reflection, als über +Annotationen ist, beenden wir diesen kleinen Ausflug mit dem Wissen, +wie die zuvor hinterlegten Meta-Informationen auch zur Laufzeit ausgelesen +werden können. Das ist nicht schwieriger als das Ermitteln der +von einer Klasse implementierten Methoden oder ihrer Modifier, wie +wir es in Abschnitt 43.3 +kennengelernt haben. + +

+Seit der Version 5 des JDK stellt das Reflection API das Interface +AnnotatedElement +zur Verfügung. Es wir von nahezu allen Reflection-Typen wie Class, +Method +oder Field +implementiert und besitzt folgende Signatur: +

+ + + + + +
+ +
+boolean isAnnotationPresent(
+   Class<? extends Annotation> annotationClass);
+
+<T extends Annotation> T getAnnotation(Class<T> annotationClass);
+
+Annotation[] getAnnotations();
+
+Annotation[] getDeclaredAnnotations();
+
+
+
+
+java.lang.reflect.AnnotatedElement
+ +

+Über die Methode isAnnotationPresent +kann festgestellt werden, ob das Element um die übergebenen Annotation +erweitert wurde und über die Methode getAnnotation +ist es möglich das Annotations-Objekt auszulesen. + +

+Die beiden letzten Methoden geben schließlich alle zu einer +Element gehörenden Annotationen in Form eines Arrays zurück. +Der Unterschied zwischen beiden ist, dass getDeclaredAnnotations +nur die tatsächlich an das Element angehangenen Metainformationen +zurückgibt, während getAnnotations +auch die geerbten Annotationen einschließt. Besitzt das Element +keinerlei Annotationen, ist das Resultat der Methoden ein Array der +Länge 0. +


+ + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3