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.

  • Source: Die Annotation ist nur im Quellcode sichtbar
  • Class: Die Annotation ist auch in der Class-Datei, also im Kompilat, vorhanden.
  • Runtime: Die Annotation wird während der Laufzeit von der JVM geladen. Nur mit dieser Policy kann eine Annotation per Reflection ausgelesen werden.
@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.

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.