06.04 Annotation
In Java ist es mit Annotationen möglich, Metainformation in den Quellcode eines Programmes einzufügen. Diese können wiederum von unterschiedlichsten Tools (oder Ihnen selbst) ausgelesen werden. So kann bspw. bereits ein Compiler einige Annotationen verwenden. Z. B. um Warnungen zu unterdrücken oder zu generieren. Sie können auf Annotationen seit Java 1.5 zugreifen.
Um Annotationen (Annotations) zu verwenden, schreiben Sie den Namen der Annotation mit einem vorangestellten @-Zeichen in Ihren Quelltext. Anschließend kann zusätzlich eine optionale, durch Kommata separierte Parameterliste in runden Klammern folgen. Um eine Methode als veraltet (deprecated) zu markieren, können Sie z. B. folgende Annotation verwenden:
public class Veraltet { @Deprecated public void dasIstEineVeralteteMethode(int undSollteNichtMehrVerwendetWerden) { System.out.println("Alt"); } }
Vordefinierte Annotationen
Es gibt in Java bereits einige vordefinierte Annotationen in verschiedenen Packages. Eine kleine Auswahl folgt:
java.lang
|
|
Name | Zweck |
@Deprecated | Markiert Elemente (Klassen, Methoden, …), die veraltet sind, oder aus anderen Gründen nicht benutzt werden sollten. Siehe auch Deprecated. |
@Override | Markiert eine Methode, die eine andere Methode überschreibt. Hat z. B. der Programmierer versehentlich einen Tippfehler beim Kopf der zu überschreibenden Methode gemacht, macht ihn der Compiler darauf aufmerksam, dass die Methode, die er zu überschreiben versucht, gar nicht in einer Elternklasse existiert. |
@SuppressWarnings | Veranlasst den Compiler einen oder mehrere Typen Warnungen nicht zu melden. |
java.lang.annotation
|
|
Name | Zweck |
@Documented | Wird für Annotationen verwendet, die von JavaDoc, und ähnlichen Programmen, dokumentiert werden sollen. Das ist insbesondere wünschenswert für Annotationen, deren Vorhandensein einen direkten Einfluss auf das Programm haben. |
@Inherited | Markiert eine Annotation, welche vererbt werden soll. Damit ist gemeint: wenn die Annotation eine Klasse markiert, sind automatisch alle Unterklassen ebenfalls markiert. |
@Retention | Regelt die Sichtbarkeit einer Annotation. Dazu wird eine RetentionPolicy gesetzt.
|
@Target | Wird ebenfalls für Annotationen angewandt. Das @Target sagt dem Compiler, welche Elemente eine Annotation er markieren darf. @Target erwartet ein Element von ElementType .
|
Eigene Annotationen
Es ist möglich, eigene Annotationen zu schreiben. Der Syntax einer Annotation gleicht der Syntax eines Interfaces. Wie ein Interface muss auch eine Annotation in einer eigenen Java-Datei gespeichert werden.
Verglichen mit einem Interface hat eine Annotation folgende Unterschiede:
- Dem Schlüsselwort
interface
wird ein @ vorangestellt. - Lediglich Methoden ohne Argumente und ohne
throws
-Klauseln sind erlaubt - Rückgabewert der Methoden dürfen alle primitiven Datentypen, String, Class, Enumerationen, Annotationen und Arrays der eben genannten sein (einige davon lernen Sie erst zu einem späteren Zeitpunkt in diesem Buch kennen).
- Methoden können einen „default“-Wert besitzen.
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface IntegerSetter { int min(); int max(); int start() default 1; }
Die hier definierte Annotation IntegerSetter
besitzt drei Elemente: min
, max
und start
. Alle drei sind vom Typ int
. Das Element start
besitzt einen Default-Wert von 1.
Retention
und Target
sind andere Annotationen, welche eine Aussage über den Gültigkeitsbereich der Annotation IntegerSetter
machen. Hier wird gesagt, dass die Annotation IntegerSetter
zur Laufzeit sichtbar ist, und nur für Methoden verwenden werden kann.
Annotation anwenden
Annotationen werden vor das zu markierende Element geschrieben, einfach indem nach einem @ der Name der Annotation ausgeschrieben wird. Falls die Annotation Elemente besitzt, müssen die Elemente noch gesetzt werden. Dazu schreibt man, in runden Klammern, Element = Wert
-Paare.
public class Point { private int x, y; @IntegerSetter(min = 0, max = 5) public void setX(int x) { this.x = x; } @IntegerSetter(min = 0, max = 20, start = 5) public void setY(int y) { this.y = y; } }
Hier werden die beiden Methoden setX
und setY
mit IntegerSetter
markiert. Da das Element start
einen Default-Wert besitzt, ist es nicht notwendig, das Element jedes Mal neu zu definieren.
Annotation zur Laufzeit auslesen
Selbstgeschriebene Annotation werden oft zur Laufzeit benötigt. Mit Reflection können die Annotation ausgelesen werden. Die meisten Reflection-Klassen bieten eine entsprechende Methode getAnnotation(s)
public static void main(String[] args) throws Exception { Point.list(Point.class); } public static void list(Class<?> clazz) throws Exception { for (Method method : clazz.getMethods()) { IntegerSetter value = method.getAnnotation(IntegerSetter.class); if (value != null) { System.out.printf("%s: min=%d, max=%d, start=%d\n", method.getName(), value.min(), value.max(), value.start()); } } }
Die Ausgabe dieses Programmes ist:
setX: min=0, max=5, start=1
setY: min=0, max=20, start=5
Wie man an dem Beispiel sieht, können Annotationen wie normale Objekte behandelt werden.
Annotationen als Kommentare
Bevor Annotationen mit Java 5 eingeführt wurden, konnten Meta-Informationen nur in Form von Kommentaren hinzugefügt werden. Dies hatte den Nachteil, dass es sehr schwierig war, bei Bedarf gezielte Informationen automatisiert aus den Klassen herauszufiltern.
Das ist natürlich nicht immer sinnvoll. Ein Kommentar, der lediglich zum besseren Verständnis des Quellcodes dient, muss natürlich nicht automatisiert ausgelesen werden.
Deshalb sind viele Annotationen nichts anderes als eine moderne Version von Kommentaren. Wurden früher bspw. der Autor, die Versionsnummer, das Erstellungs- und das Veränderungsdatum einer Klasse in Form von Kommentaren hinterlegt (
// Autor: Stefan Kiesel // Version: 1.0 // Datum: 01.10.2008 // Verändert am: 25.11.2008 public class MyClass {}
), so kann dies jetzt über eine entsprechende Annotation realisiert werden.
public @interface ClassInformations { String autor(); String erstellt(); String veraendert() default "nie"; double version() default 1.0; }
@ClassInformations(autor = "Stefan Kiesel", erstellt ="1.10.2008", veraendert = "25.11.2008") public class MyClass {}
Aber Annotationen haben noch viele andere Einsatzorte. Z. B. werden wir Sie später im Buch in Kombination mit Mapping einsetzen, und so auch den Umgang mit Annotationen vertiefen.