Aşağıda @Deprecated ve @Override gibi öntanımlı annotation'ları (predefined annotation) kullanılan bir sınıf gözükmektedir:
package com.test.annotation;
public class PredefinedAnnotations {
int x=1;
public int getX(){
return x;
}
public void setX(int x){
this.x=x;
}
@Deprecated
public void setXValue(int x){
this.x=x;
}
@Override
public String toString() {
return "x:"+x;
}
}
setXValue method'u @Deprecated ile deprecated edilmiştir. toString method'unda ise Object sınıfın toString method'unun override edileceği belirtilmiştir. Örneğin yanlış olarak
@Override
public String tostring() {
return "x:"+x;
}
yazarsak, derleyici tostring adında override edilen bir method'un olmadığını söyler ve hata yapmanızı engeller:
The method tostring() of type PredefinedAnnotations must override or implement a supertype method
Yukarıdaki sınıfı aşağıdaki gibi kullanalım
package com.test.annotation;
public class OtherClass {
@SuppressWarnings("deprecation")
public OtherClass() {
PredefinedAnnotations predefinedAnnotations=new PredefinedAnnotations();
predefinedAnnotations.setXValue(15);
System.out.println(predefinedAnnotations.getX());
}
}
setXValue deprecated bir method olmasından dolayı derleyi uyarı verecektir. Bu uyarının verilmemesi için @SuppressWarnings("deprecation") eklenmiştir.
Print adında bir annotation yaratıyoruz. Bu annotation eğer verilmez ise sistem çıktısına herhangi bir şey basılmamaktadır. Eğer simple verilirse basit bir çıktı, full verilirse daha açıklamalı bir bilgi basılacaktır. Bunun için aşağıdaki gibi bir annotation'ı yaratabiliriz:
package com.test.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Print {
// simple veya full olabilir
String model() default "none";
}
@interface ifadesi bunun bir Annotation olduğunu belirtir. @Target(ElementType.METHOD) ile sadece method'lar için olduğunu belirtiyoruz. @Retention(RetentionPolicy.RUNTIME) ile de sadece derleme zamanında çalışacağını belirtir. String model() default "none" ile model değişkeni yaratıyoruz ve varsayılan değerini none yapıyoruz.
Aşağıdaki gibi bir interface olsun :
public interface Operation {
public int operate(int p1, int p2);
}
Bu interface iki int alır ve bir int döner. Bir Operator sınıfımız olsun ve verilen bir Operation nesnesinin operate method'u çağırsın ve operasyonu gerçekleştirsin. Operation sınıfı operate method'un Print annotation'u olup olmadığını kontrol eder. Eğer var ise ona göre operate işlemini yaptıktan sonra print işlemini yapar. Operator sınıfı aşağıdaki gibidir :
package com.test.annotation;
import java.lang.reflect.Method;
public class Operator {
private int p1;
private int p2;
public Operator(int p1,int p2) {
this.p1=p1;
this.p2=p2;
}
public int operate(Operation operation){
// kütüphane ile ilgili ek bir şeyler yapar
int result = operation.operate(p1, p2);
try {
Method method=operation.getClass().getMethod("operate", int.class, int.class);
if(method.isAnnotationPresent(Print.class)){
Print printAnnotation=method.getAnnotation(Print.class);
if(printAnnotation.model().equals("simple")){
System.out.println(p1+","+ p2 + " = "+ result);
}else if(printAnnotation.model().equals("full")){
System.out.println(p1 +" ve " + p2 +" operasyona girdi. Sonuç : "+result);
}
}
} catch (Exception e) {}
// kütüphane ile ilgili ek bir şeyler yapar
return result;
}
}
Operator operasyona sokacağı iki değeri en baştan alıyor. operate fonksiyonu, hangi operasyonu yapacağını parametre olarak alıyor. İlk önce int result = operation.operate(p1, p2) şeklinde operasyonu gerçekleştiriyor. Sonra Print annotation'unun kullanılıp kullanılmadığı kontrol ediliyor. Bunun için önce
Method method=operation.getClass().getMethod("operate", int.class, int.class);
ile operate method'u alınıyor. Ardından
if(method.isAnnotationPresent(Print.class))
kontrolü ile Print annotation'un kullanılıp kullanılmadığına bakıyor. Eğer kullanılıyor ise annotation'u alıyor :
Print printAnnotation=method.getAnnotation(Print.class);
Ardından model değerine göre print işlemini gerçekleştiriyor.
Şimdi bu sınıfları kullanan bir uygulama yapabiliriz. Aşağıdaki gibi toplama ve çarpma için iki operasyon sınıfı tanımlıyoruz. Toplama için :
package com.test.annotation;
public class SumOperation implements Operation {
@Override
@Print(model="simple")
public int operate(int p1, int p2) {
return p1+p2;
}
}
Çarpma için ise :
package com.test.annotation;
public class MultiplyOperation implements Operation {
@Override
@Print(model="full")
public int operate(int p1, int p2) {
return p1*p2;
}
}
Toplama işlemi @Print(model="simple") ile basit modeli seçmişken, çarpma işlemi için @Print(model="full") ise açıklamalı bilginin basılması istenmiştir. Bu iki sınıfı kullanarak uygulama aşağıdaki gibi test edilebilir:
package com.test.annotation;
public class MyOperationApp {
public static void main(String[] args) {
SumOperation sumOperation=new SumOperation();
sumOperation.operate(10, 12);
MultiplyOperation multiplyOperation=new MultiplyOperation();
multiplyOperation.operate(10, 12);
//operator üzerinden yapılırsa ekrana basılacak bilgiler
Operator operator=new Operator(10, 12);
operator.operate(sumOperation);
operator.operate(multiplyOperation);
}
}
İlk operasyon işlemlerinde ekrana hiç bir bilgi basılmayacaktır:
SumOperation sumOperation=new SumOperation();
sumOperation.operate(10, 12);
MultiplyOperation multiplyOperation=new MultiplyOperation();
multiplyOperation.operate(10, 12);
Ancak Operator sınıfını kullanarak operasyon yapılırsa istenildiği gibi çıktıda bilgiler görünecektir. Uygulama çalıştığında aşağıdaki gibi bir çıktı oluşur:
10,12 = 22
10 ve 12 operasyona girdi. Sonuç : 120
Görüldüğü gibi bir Print annotation'ı yarattık ve onun kullanılmasını sağladık.