2015.02.03 14:10 tak działają anotacje w Javie

Oto jak (patrz http://sjp.pwn.pl/poradnia/haslo/Oto-co;14326.html ) działają javowe anotacje.

Pierwsze przybliżenie jest takie:

Typ anotacyjny (czyli to, co tworzymy pisząc @interface) jest interfejsem dziedziczącym po interfejsie java.lang.annotation.Annotation. Jego elementy (tak się fachowo nazywają te parametry, którym się podaje argumenty w nawiasach przy oznaczaniu czegoś anotacją) są metodami tego interfejsu. Zapis @interface MojaAnotacja ... jest tylko lukrem syntatycznym na to.

Kiedy oznaczam klasę anotacją, to – wbrew temu, co można by myśleć – ta klasa nie implementuje przez to tego interfejsu. No bo przecież tak by to nie mogło działać, bo nie tylko klasy można anotować, ale na przykład też atrybuty, a atrybut nie może implementować interfejsu. Jest inaczej. Kiedy oznaczam coś anotacją, tworzę obiekt anonimowej klasy implementującej ten interfejs, którym jest typ anotacyjny. Jeśli przy tym anotowaniu podaję argumenty, to czarodziejsko są w tej anonimowej klasie tworzone metody implementujące te metody interfejsu, którym jest typ anotacyjny, które zostały czarodziejsko stworzone, kiedy tworząc typ anotacyjny dałem mu elementy, i te metody w tej anonimowej klasie zwracają to, co podałem w tych argumentach.

Dowodzi tego wszystkiego ten przykład:

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface MojaAnotacja {
    String kuku();
    String ryku();
}

@MojaAnotacja(kuku="czarna", ryku="krowa")
public class Dwa {
  public static void main(String[] args) {
    Annotation[] anotacje = Dwa.class.getAnnotations();
    for (Annotation anotacja : anotacje) {
      System.out.println("ta klasa jest oznaczona anotacją " + anotacja);
      System.out.println("Ta anotacja jest jakby obiektem klasy " + anotacja.getClass().getName());
      boolean implementuje = anotacja instanceof MojaAnotacja;
      System.out.println("A ta klasa " + (implementuje ? "" : "nie ") + " implementuje interfejs MojaAnotacja");
      System.out.println("Tan obiekt, którym jest anotacja, ma metodę kuku zwracającą " + ((MojaAnotacja) anotacja).kuku());
    }
  }
}

Drugie przybliżenie jest takie:

Ale jeśli spróbuję tak po prostu, bez lukru syntaktycznego, stworzyć interfejs dziedziczący po java.lang.annotation.Annotation, nie stworzę w ten sposób typu anotacyjnego – nie będę mógł takim interfejsem anotować niczego. Dowodzi tego fakt, że ten przykład się nie kompiluje:

import java.lang.annotation.Annotation;

interface MojaAnotacja extends Annotation { }

@MojaAnotacja(kuku="czarna", ryku="krowa")
public class Dwa { }

Nie do końca też jest jest prawdą, że anotując coś tworzę obiekt anonimowej klasy implementującej ten interfejs, którym jest typ anotacyjny. Tak naprawdę to tylko tak w przybliżeniu wygląda, kiedy oglądam oanotowaną rzecz przez introspekcję. A naprawdę to kompilator w generowanym bajtkodzie z opisem tej klasy po prostu podaje przy danej rzeczy nazwę typów anotacyjnych, którymi oanotowaliśmy tę rzecz, i ewentualnie nazwy i wartości argumentów, które podaliśmy przy tych anotacjach. O czym mówi dokumentacja, tu: http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16

Ale ten typ anotacyjny naprawdę jest interfejsem. I można zrobić, żeby jakaś klasa implementowała ten interfejs – tylko trzeba zaimplementować metody powstałe z elementów typu anotacyjnego i metodę annotationType z interfejsu Annotation. Ale przez zaimplementowanie interfejsu, którym jest typ anotacyjny, klasa nie zostaje oanotowana tym typem anotacyjnym. Tego wszystkiego dowodzi ten przykład:

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface MojaAnotacja {
    String kuku();
    String ryku();
}

public class Dwa implements MojaAnotacja {
  public String kuku() {
    return "czarna";
  }
  public String ryku() {
    return "krowa";
  }
  public Class annotationType() {
    return MojaAnotacja.class;
  }
  public static void main(String[] args) {
    Annotation[] anotacje = Dwa.class.getAnnotations();
    System.out.println(anotacje.length);
  }
}

Rzadko się to w praktyce przydaje, ale przydaje się to na przykład przy korzystaniu (przy okazji CDI) z klasy AnnotationLiteral.



komentarze:

ksywa:

tu wpisz cyfrę cztery: (to takie zabezpieczenie antyspamowe)

komentarze wulgarne albo co mi się nie spodobają będę kasował


powrot na strone glowna

RSS