17 Eylül 2011 Cumartesi

Java'da Belirtim (Annotation) Kullanımı

Java belirtimleri Java kaynak koduna eklenen sözdizimsel üst-bilgi olarak düşünülmelidir. Belirtimler sayesinde sınıf, metot, saha gibi temel programlama yapılarını işaretlemek ve bu yapılara ek bilgi yüklemek mümkün hale gelmiştir.

Belirtimler, program akışını doğrudan etkilemezler. Fakat işaretlenmiş (üzerine bir belirtim eklenmiş) yapılara ek bilgi sağlayıp, çalışma zamanında bu yapıların ne şekilde kullanılması gerektiğini bildirebilirler. Tabi ki bunun için bu belirtimleri yorumlayıp ne yapılacağına karar veren programın da kodlanmış olması gerekir.

Kullanıcı tanımlı Java Belirtimleri
Java, JDK tarafından sağlanan belirtim tipleri dışında kendi tiplerimizi de oluşturmamıza olanak verir. Bunun için "@" işareti ile belirtilen özel bir arayüz (interface) tanımı yapılmalıdır. Örneğin, aşağıdaki kod parçasıyla @TestMetodu isimli bir belirtim oluşturup bunu test amaçlı metotları işaretlemek için kullanabiliriz (bkz. OrnekTestSınıfı.testMetodu()).

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestMetodu {
}

public class OrnekTestSınıfı {
@TestMetodu
public void testMetodu() {
System.out.println("Bu bir test metodudur.");
}
}

@TestMetodu belirtimi tanımlanırken iki üst-belirtim (meta-annotation) kullanılmıştır: @Target ve @Retention. @Target, tanımladığımız belirtimin hangi program ögelerine uygulanabileceğini ifade eder. Örneğimizdeki gibi tek bir öge tipi alabileceği gibi birden çok tipi de belirtebilir (örn. @Target({ElementType.METHOD, ElementType.FIELD})). Alabileceği değerler şöyledir (bkz. java.lang.annotation.ElementType): TYPE (sınıf ve arayüzler), FIELD (sınıf sahaları), METHOD (metotlar), PARAMETER (metot parametreleri), CONSTRUCTOR (yapılandırıcılar), LOCAL_VARIABLE (yerel değişkenler), ANNOTATION_TYPE (belirtim tanımları, üst-belirtim olarak), PACKAGE (Java paketleri).

@Retention belirtimi ise işaretlenen belirtimin Java sanal makinesi (JVM) tarafından nasıl ve ne kadar süre saklanacağını söyler ve RetentionPolicy.{SOURCE, CLASS, RUNTIME} değerlerinden birini alabilir. SOURCE ile işaretlenmiş belirtimler derleme süresince derleyici tarafından okunurlar ve üretilen Java .class dosyasında yer almazlar. CLASS (varsayılan değer) kalıcılığına sahip belirtimler ise derleyici tarafından .class dosyasına konurlar ancak çalışma zamanında erişilemezler. Son olarak RUNTIME kalıcılık politikası ile belirtimler, çalışma zamanında Java yansıma (reflection) kütüphanesi ile erişilebilir halde saklanırlar.

Belirtim Parametreleri
Java belirtimleri, Java ögelerini sadece işaretlemek için kullanılabilecekleri gibi (örn. @TestMetodu belirtimi) bu ögelere ek bilgiler yüklemek için de kullanılabilirler. Örneğin, @Yazar("ovunccetin") gibi bir belirtim ifadesi, işaretlenmiş olan Java ögesinin kim tarafından yazıldığını açıklayabilir. Bu tip, bilgi yükleyici belirtimler yapabilmek için belirtim tanımlarına parametre eklenmelidir. Aşağıdaki, @Yazar tanımında value() metodu ile belirtimin yazar ismini parametrik olarak alması sağlanmıştır (value kelimesi Java belirtimleri için özel bir kelimedir ve parametre ismi kullanmadan değer atanabilmesini sağlar. Yani, @Yazar(value = "ovunccetin") yerine doğrudan @Yazar("ovunccetin") yazılabilir. @Yazar belirtiminde value() yerine isim() diye bir parametre kullanmış olsaydık bu durumda @Yazar(isim = "ovunccetin") kullanımı zorunlu olacaktır.).

Belirtim parametrelerine varsayılan değer atanmadığı takdirde, ilgili belirtim kullanılırken bu parametrelere değer atanması zorunludur, aksi takdirde derleme hatası oluşacaktır. Örneğin, aşağıdaki @Yazar belirtiminde aciklama parametresine varsayılan değer atanmıştır. Yani, @Yazar("ovunccetin") şeklindeki kullanımda aciklama parametresi varsayılan değerini ("") alacaktır.  @Yazar(aciklama = "Açıklama...") şeklindeki kullanım ise value parametresinin varsayılan değeri olmadığından derleme hatasına yol açacaktır.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Yazar {
public String value();
public String aciklama() default "";
}

Yansıma Kütüphanesi ile Belirtimlerin Okunması
Belirtimler tek başlarına program akışına etki etmezler. Bunların geliştirici kodu tarafından okunması ve yorumlanması gerekir. Bunun için Java Yansıma (java.lang.reflect) kütüphanesi kullanılmaktadır. Bununla ilgili bir örnek aşağıda verilmiştir.

public class OrnekSinif {
   @Yazar("ovunc")
   public void method1(){}
   public void method2(){}
   @Yazar("ali")
   public void method3(){}
}

public class MetotYazdir {
public static void main(String[] args) {
   // OrnekSinif'i içindeki public metotlar...
   Method[] metotlar = OrnekSinif.class.getMethods();
   for (Method m : metotlar) {
      // Metot üzerindeki @Yazar belirtimi...
      Yazar yz = m.getAnnotation(Yazar.class);
      if (yz != null) { // Belirtim var mı?
         String msg = m.getName() + "(): " + yz.value();
         System.out.println(msg);
      }
   }
}
}

// Ekran çıktısı aşağıdaki gibi olacaktır.
method1(): ovunc
method3(): ahmet

Hiç yorum yok:

Yorum Gönder