1~

Minter Coder's Blog

EK - Java Annotations (Açıklamalar) 2

2021-07-01

Ikinci bir reflection örneği :

Önceki örnekte myMethod() parametrelere sahip değildi.Böylece , getMethod() çağrıldığında , sadece myMethod() ismi geçildi.Ancak , eğer ki bir method parametrelere sahipse ve bunu elde etmek istiyorsak , parametrelerinin türlerini temsil eden objecleri argüman olarak belirtmeliyiz.Hemen örneğimizi inceleylim

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
    String str();
    int val();
}

class Meta{ @MyAnno(str="Benim Kerem",val = 32) public static void myMethod(String myString,int myValue){ Meta ob = new Meta(); try{ Class<?> c = ob.getClass(); Method m = c.getMethod("myMethod",String.class,int.class); MyAnno myAnno = m.getAnnotation(MyAnno.class); System.out.println(myAnno.val()+" "+myAnno.str()); System.out.println("Parametreler ve değerleri : "+myString+" "+myValue); }catch(NoSuchMethodException exc){ System.out.println("Method Not Found."); } }

<span style="color:#cc7832">public static void </span>main(String[] args) {
    myMethod(<span style="color:#6a8759">&quot;Kerem&quot;</span><span style="color:#cc7832">,</span><span style="color:#6897bb">32</span>)<span style="color:#cc7832">;

} }

Çıktımız :

32 Benim Kerem
Parametreler ve değerleri : Kerem 32


Bu versiyonda , myMethod() bir String ve bir int parametresi alıyor.Bu method hakkında bilgi elde etmek için , getMethod() aşağıdaki gibi çağrılmalıdır.

      Method m = c.getMethod("myMethod",String.class,int.class);

Burda , Class String ve int temsil eden Class nesneleri ek argümanlar olarak verildi.


Bütün Annotationları Elde etme :

Bir öğeyle ilişkili RUNTIME retention(saklama) sahip bütün annotationnları getAnnotations()  methodunu çağırarak elde edebilirsiniz.Genel şekli böyledir :

       Annotation[ ] getAnnotations( )


Annotationların bir dizisini geri döndürür.getAnnotations() Class,Method,Constructor ve Field object türlerinin üzerinde çağrılabilir.

Aşağıda bir class ve bir methodla ilişkili tüm annotationları nasıl elde edilir ile ilgili bir örnek var hemen bunu inceleyelim :

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

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno{
    String str();
    int value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface What{
    String description();
}

@What(description = "Class aciklama kismi") @MyAnno(str = "Class String degeri",value = 1) public class MyFile{

<span style="color:#bbb529">@What</span>(description = <span style="color:#6a8759">&quot;Method aciklama kismi&quot;</span>)
<span style="color:#bbb529">@MyAnno</span>(str = <span style="color:#6a8759">&quot;Method String degeri&quot;</span><span style="color:#cc7832">,</span>value = <span style="color:#6897bb">2</span>)
<span style="color:#cc7832">public static void </span><span style="color:#ffc66d">myMeth</span>(){
    <span style="color:#cc7832">try </span>{
        MyFile myFile = <span style="color:#cc7832">new </span>MyFile()<span style="color:#cc7832">;

// class için bütün annotationlar Annotation annos[] = myFile.getClass().getAnnotations(); System.out.println(" Class için annotationlar "); for (Annotation a : annos) { System.out.println(a); } System.out.println(); System.out.println(); // method için bütün annotationlar System.out.println(" Method için annotationlar "); Method method = myFile.getClass().getMethod("myMeth"); annos = method.getAnnotations(); for(Annotation a : annos){ System.out.println(a); }

    }<span style="color:#cc7832">catch</span>(NoSuchMethodException e ){
        e.printStackTrace()<span style="color:#cc7832">;

}

}

<span style="color:#cc7832">public static void </span>main(String[] args) {
    myMeth()<span style="color:#cc7832">;

} }

Programın çıktısı :

**** Class için annotationlar ****
@What(description=Class aciklama kismi)
@MyAnno(str=Class String degeri, value=1)


**** Method için annotationlar ****
@What(description=Method aciklama kismi)
@MyAnno(str=Method String degeri, value=2)


Program MyFile sınıfı ve myMeth() methoduyla ilişkili tüm annotationların bir dizisini elde etmek için getAnnotations() kullanıyor.Açıklandığı gibi , getAnnotations() Annotation nesnelerinin bir dizisini geri dönderiyor.Tekrar hatırlatalım şunu , Annotation bütün annotationların bir super-interface'dir ve toString() methodunu da override eder.Böylece , bir Annotation'a çıktı referenas edildiğinde , onun bir string üretmek için onun toString() methodu çağrılır, yukarıdaki örneğin çıktısında gösterdiği gibi.

 

AnnotatedElement Interfacesi :

java.lang.reflect packagesinde tanımlı olan AnnotatedElement interfacesi , bu interface tarafından tanımlanmış getAnnotation() ve getAnnotations() methodları önceki örneklerde kullanıldı.Bu interface annotationlar için reflection destekler ve Method,Field,Constructor,Class ve Package , ve diğerleri tarafından implement edilmiştir.

getAnnotation() ve getAnnotations() methodlarına ek olarak , AnnotatedElement birkaç farklı methodlar daha tanımlıyor.İki tanesi annotationların ilk olarak Java'ya eklendiğinden beri mevcuttur.Birincisi getDeclaredAnnotations() , genel görünümü :

         Annotation[ ] getDeclaredAnnotations( )


Çağıran objede mevcut non-inherited annotationları tümünü geri dönderir.İkincisi isAnnotationPresent() , genel görünümü :

      default boolean isAnnotationPresent(Class<? extends Annotation> annoType)


Çağıran nesne ile annoType tarafından belirtilmiş annotation eğer ilişkiliyse true dönderir.Diğer durumda false geri dönderir.Bunlara, JDK 8 getDeclaredAnnotation(),getAnnotationsByType(), ve getDeclaredAnnotationsByType() methodlarını ekledi.Bunlardan son ikisi otomatik olarak tekrarlı annotationla çalışır (Repeated Annotationlar ilerleyen bölümlerde açıklandı).

 

Default Değerler Kullanma :

Eğer ki annotation uygulandığında herhangi bir değer verilmemişse default değerler kullanılacak , annotation üyelerine de default değerler verebilirsiniz.Bir default değer default cümleceğini üyenin bildirimine ekleyerek belirtilir.Genel formu bu biçimdedir :

           type member( ) default value ;

Burda value , type ile uygun türde olmak zorundadır.

Aşğıda @MyAnno'yu default değerler ekleyerek tekrar yazdık :

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno{
    String str() default "Default degeri girdim";
    int value() default 42;
}

 

Yukarıda gördüğünüz gibi str ve val değerlerine default olarak değerlerimizi girdik.Bu default değerleri kullanmak , @MyAnno kullanıldığında hiçbir değerin üyeler için belirtilmiş olmasına ihtiyaç duymaz , çünkü default değerleri girdik.Bu nedenle aşağıdaki 4 yol @MyAnno için kullanılabilir :

@MyAnno // burda 2 deger de default
@MyAnno(str="Default 2.deger") // burda val kısmı default
@MyAnno(str="Default 2.deger",value = 333) // burda ikisi de girilen deger
@MyAnno(value = 421412) // burda str kısmı default olarak gelecek

Aşağıdaki örnekte default değerleri görebiliriz :

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno{
    String str() default "Default degeri girdim";
    int value() default 42;
}
public class MyFile{
    @MyAnno()
    public static void myMeth(){
        try{
            Class<?> myClass = MyFile.class;
            Method myMethod = myClass.getMethod("myMeth");
            MyAnno myAnno = myMethod.getAnnotation(MyAnno.class);
            System.out.println(myAnno.str()+" "+myAnno.value());
        }catch(NoSuchMethodException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        myMeth();
    }

}

 

Çıktı :

Default degeri girdim 42

 

 

Marker (işaretleyici) Annotations(açıklamalar) :

Bir market annotation hiçbir üye içermeyen özel bir annotation türüdür.Amaç sadece bir öğeyi işaretlemektir.Böylece , onun bir annotation olarak varlığı yeterlidir.Eğer ki bir işaretleyici annotationun mevcut ise onu belirlemek için en iyi yol isAnnotationPresent() methodunu kullanmaktır , ki bu method AnnotatedElement interfacesinde tanımlıdır.

Aşağıdaki örnek bir market annotationu kullanır.Bir işaretleyici interface üye içermediğinden , sadece mevcut olup olmadığını belirlemek yeterlidir.

@Retention(RetentionPolicy.RUNTIME)
@interface MyMarkerAnnotation{ }
public class MyFile{
    @MyMarkerAnnotation
    public static void myMeth(){
        try {
            Method myMethod = MyFile.class.getMethod("myMeth");
            if(myMethod.isAnnotationPresent(MyMarkerAnnotation.class)){
                System.out.println("MyMarkerAnnotationu mevcuttur.");
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
}
<span style="color:#cc7832">public static void </span><span style="color:#ffc66d">main</span>(String[] args) {
    <em>myMeth</em>()<span style="color:#cc7832">;

} }

Çıktı :

MyMarkerAnnotationu mevcuttur.

 

Tekli-Üye (Single-Member) Açıklamaları(Annotations) :

 

Bir tekli-üye annotation sadece bir üye içerir.Bu annotation üyenin değerini belirtmenin kısa yol biçimini göstermene izin verir bunun dışında bir normal annotation gibi çalışır.Bir üye mevcut olduğunda , annotation uygulandığında üye için değeri basitçe belirtebilirsiniz.-üyenin ismini belirtmeye ihtiyacınız yoktur.Ancak , bu kısa yolu kullanma sırasında , üyenin ismi value olmak zorundadır.Basit bir örnek verelim bu örnek bir single-member annotationu kullanıyor.

 

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MySingle{
    int value(); // bu değişkenin değeri value olmak zorundadır.Eğer ki başka bir isim yaparsanız aşağıda göstermek zorundasınız
    // örneğin @MySingle(12) yerine buraya yazdığınız değişkenin ismini belirtip ornekdegisken = 12 yapmak zorundasınız.
}

public class MyFile{ @MySingle(12) public static void myMeth(){ try { Method myMethod = MyFile.class.getMethod("myMeth"); MySingle mySingle = myMethod.getAnnotation(MySingle.class); System.out.println(mySingle.value()); } catch (NoSuchMethodException e) { e.printStackTrace(); }

}
<span style="color:#cc7832">public static void </span><span style="color:#ffc66d">main</span>(String[] args) {
    <em>myMeth</em>()<span style="color:#cc7832">;

} }

Çıktı :

12

"value =" şeklinde bir belirtme olmadığına dikkat edin.Eğer ki şöyle bir şey yapmak isterseniz :

@Retention(RetentionPolicy.RUNTIME)
@interface MySingle{
    int value(); 
    String myName() default "Kerem";
}

Bu durumda yine

@MySingle(12)

kullanabilirsiniz sıkıntı yok , ama şöyle yaparsanız

@Retention(RetentionPolicy.RUNTIME)
@interface MySingle{
    int value();
    String myName();
}

bu durumd ayapmanızz gereken :

@MySingle(myName = "Kerem",value = 42)

 

Yerleşik,Gömülü (Built-in) Annotationlar :

Java çok yerleşik annotation tanımlar.Çoğu özeldir , fakat 9 tanesi genel amaçlıdır.Bunlardan 4'ü java.lang.annotation packagesinden import edilir : @Retention,@Documented,@Target ve @Inherited.5 tanesi ise : @Override,@Deprecated,@FunctionalInterface,@SafeVarargs , ve @SuppressWarnings , bunlar da java.lang içerisinde yer alıyor.Her birini tek tek açıklayalım.

 

@Retention

Retention sadece başka bir annotationa (açıklamaya) bir açıklama (annotation) olarak kullanılak için tasarlanmıştır.Bu önceden de açıklandığı gibi retention policy(saklama politikasını) gösteriyor.

@Documented

Bu annotation bir marker interface(işaretleyici arayüz)dir bu arayüz de bir tool'a şunu söyler bir annotation dökümanlanacak,belgelenecek.Bu sadece başka bir annotation (açıklama)bildirimine bir açıklama olarak kullanılır.

@Target

Bu annotation bir annotationun uygulanabilir olacağı öğelerin türlerini belirtir.Sadece başka bir annotationa bir açıklama olarak tasarlanmıştır.@Target ElementType enumerationun sabitlerinden oluşan sadece bir dizi argüman alır.Bu argüman annotationun uygulanabilir olduğu bildirimlerin türlerini belirtir.Sabitler aşağıda


Target Constant Annotation uygulanabieceği yer
ANNOTATION_TYPE Diğer annotation
CONSTRUCTOR Constructor
FIELD Field
LOCAL_VARIABLE Local Variable(yerel değişken)
METHOD Method
MODULE Module
PACKAGE Package
PARAMETER Parameter
TYPE Class,interface yada enumeration
TYPE_PARAMETER Tür parametresi
TYPE_USE Tür kullanımı

 

Arkadaşlar yukarıdakileri ezberlemeye gerek yok sadece kısa bi göz gezdirin devam edelim.

Bir @Target annotationun içerisinde bir veya birden fazla bu değerleri kullanabilirsiniz.Çoklu değer belirtmek için , onları süslü parantezler ile belirtmelisiniz.Örneğin , bir annotationun sadece alanlara(fields) ve local variable(yerel değişken)lere uygulanacağını göstermek için , şunu kullanabilirsiniz.

@Target({ElementType.FIELD,ElementType.LOCAL_VARIABLE})

Eğer ki siz @Target'i kullanmazsanız , tür parametreleri dışında , annotation herhangi bir bildirimde kullanılabilir.

 

@Inherited

Bu bir marker annotation(işaretleriyici açıklama)dır.Sadece başka bir annotation üzerinde kullanılabilir.Bu sadece sınıf bildirimleri üzreinde klullanılacak annotationları etikler.@Inherited, bir üst sınıfın annotationun bir alt sınıf tarafından devralınmasına neden olur. Bu nedenle , eğer ki bir alt sınıfa annotation talebi yapıldığında , o açıklama alt sınıfta yoksa , üst sınıf kontrol edilir.Eğer ki annotation süperclass da mevcut ise , ve @Inherited ile annotated edilmişse , o zaman bu açıklama döndürülür.

Mükemmel örnek :

import java.lang.annotation.*;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface InheritedAnnotationType{

} @Retention(RetentionPolicy.RUNTIME) @interface UninheritedAnnotationType{

} @UninheritedAnnotationType class A{

} @InheritedAnnotationType class B extends A{

} class C extends B{

} public class MyFile{ public static void main(String[] args) { System.out.println(new A().getClass().getAnnotation(InheritedAnnotationType.class)); System.out.println(new A().getClass().getAnnotation(UninheritedAnnotationType.class)); System.out.println(""); System.out.println(new B().getClass().getAnnotation(InheritedAnnotationType.class)); System.out.println(new B().getClass().getAnnotation(UninheritedAnnotationType.class)); System.out.println(""); System.out.println(new C().getClass().getAnnotation(InheritedAnnotationType.class)); System.out.println(new C().getClass().getAnnotation(UninheritedAnnotationType.class)); } }

 

Çıktı :

null
@UninheritedAnnotationType()
*****************************************************************
@InheritedAnnotationType()
null
*****************************************************************
@InheritedAnnotationType()
null

Kodu okuyup ,  anlamaya çalışın daha iyi bir şekilde aklınızda oturacak.

@Override

@Override bir marker annotationdur sadece methodlar üzerinde kullanılabilir.Bir methodun @Override olarak işarretlemenesi bir superclassdan bir methodu ezmesi ile olmak zorundadır.

@Deprecated

Bu annotation bir bildirimin modası geçmiş ve kullanılması için önerilmez olduğunu gösterir.

@FunctionalInterface

Bu annotation bir marker annotationdur interfaceler üzerinde kullanılması için tasarlanmıştır.Bunun belirtildiği interfacede , interface'in bir functional interface olduğunu gösterir.Bir functional interface de sadece ve sadece bir abstract methodu içeren interfacedir.

@SafeVarargs

Bu annotation bir marker annotationdur methodlara ve constructorlara uygulanabilir.Bir varargs parametresiyle ilgili güvenli olmayan hiçbir eylemin gerçekleşmediğini gösterir. Methodlar ayrıca static final veya private olmak zorundadır.

public class MyFile{
    @SafeVarargs
    final void display(List<String>... products) {
        for (List<String> product : products) {
            System.out.println(product);
        }
    }
    public static void main(String[] args) {
        MyFile p = new MyFile();
        List<String> list = new ArrayList<String>();
        list.add("Laptop");
        list.add("Tablet");
        p.display(list);
    }
}

@SuppressWarnings

Compiler tarafından gösterilen bir veya daha fazla uyarıyı bastırmak için kullanılır.

 

Annotationda son dersimiz olan 3.bölümde görüşürüz :)