CDI – @Qualifier Notasyonu
Seçiciler (Qualifiers), Dependency Injection kütüphaneleri için ortak olarak sunulan mekanizmalardır. Kullanılan DI konteyner ortamında aynı nesne türünden birden fazla enjekte edilebilir kaynak bulunduğunda, hangisinin seçileceğini seçme olayı, Seçicilerin çıkış noktasını oluşturur.
Örneğin yukarıdaki şekliyle Arac sınıfı türünden iki somut sınıf, uygulamanız içerisinde bulunuyor olsun. Konteyner ortamında birden fazla Arac uygulayıcısı (Araba ve Traktor) bulunacağından, CDI konteyner hangi türden nesnenin enjekte edileceğini bilemez ve çalışma anında CDI konteyner tarafından birden fazla enjekte edilebilir aday olduğuna dair hata alınır.
İşte tamda bu noktada CDI ortamının Seçici mekanizması devreye girer.
public interface Arac { int hizSoyle(); String calis(); }
Yukarıdaki gibi bir Arac sözleşmesi elde bulunuyor olsun.
@Default // Olmasada olur public class Araba implements Arac{ public String calis() { return "Araba "+hizSoyle()+" km. hızında çalışıyor.."; } public int hizSoyle(){ return ThreadLocalRandom.current().nextInt(20, 240) ; } }
Araba ve Traktor sınıfları, Arac arayüz sınıfı türünden somut sınıflardır.
@Default // Olmasada olur public class Traktor implements Arac { public String calis() { return "Traktör "+hizSoyle()+" km. hızında çalışıyor.."; } public int hizSoyle(){ return ThreadLocalRandom.current().nextInt(20, 110) ; } }
Yukarıdaki Arac arayüzü ve bu arayüzü sağlayan Araba ve Traktor sınıfları görülmektedir. Bu sınıfları kullanacak Galeri sınıfı ise aşağıda görüldüğü gibidir.
public class Galeri { @Inject private Arac arac; public static void main(String[] args) { Weld weld = new Weld(); WeldContainer konteyner = weld.initialize(); Galeri galeri = konteyner.instance().select(Galeri.class).get(); String mesaj=galeri.arac.calis(); System.out.println("> "+mesaj); } }
Galeri sınıfı çalıştırıldığında, aşağıdaki gibi bir hata mesajı bizi karşılar.
Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [Arac] with qualifiers [@Default] at injection point [[field] @Inject private com.kodcu.Galeri.arac]. Possible dependencies [[Managed Bean [class com.kodcu.Traktor] with qualifiers [@Any @Default], Managed Bean [class com.kodcu.Araba] with qualifiers [@Any @Default]]] at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:314) at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280) at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:143) at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:163) at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:382) at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:367) at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:379) at org.jboss.weld.bootstrap.api.helpers.ForwardingBootstrap.validateBeans(ForwardingBootstrap.java:85) at org.jboss.weld.environment.se.Weld.initialize(Weld.java:134) at com.kodcu.Galeri.main(Galeri.java:20) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Çünkü CDI konteyner Araba türünden mi yoksa Traktor türünden bir nesnenin mi enjekte edileceğini bilemez. Bunu geliştiriciden bekler.
CDI ortamında bu iş için @Qualifier notasyonu kullanılmaktadır. Fakat bu notasyon, Spring Framework dahilinde bulunan @Qualifier notasyonuyla karışıtırılmamalıdır. Spring’in seçici notasyonu global alanlarda, metod ve kurucu metod üzerinde yekpare tanımlanabilirken, CDI’in seçici notasyonu, harici olarak oluşturulan bir notasyon sınıfına eklenir. @Qualifier notasyonunun eklendiği sınıf ise, bu sayede, seçicilik özelliğini sağlayan bir notasyon haline bürünür.
@Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documented public @interface Qualifier {}
Yukarıda yer alan @Qualifier notasyon sınıfının, @Target notasyonuna bakıldığında, bu notasyonun sadece bir notasyon sınıfına uygulanabileceği görülebilmektedir.
Örnek olarak, @Qualifier özelliği katılmış bir notasyon sınıfı aşağıdaki gibi tanımlanabilir.
@Qualifier // Seçici özellik bu notasyona (TraktorSecici) katılıyor. @Target({ElementType.TYPE,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface TraktorSecici { }
Bu andan itibaren, TraktorSecici isimli notasyon sınıfı, seçici özellik katılmış bir Java notasyonu haline bürünür. Örneğin: Galeri sınıfı içerisindeki enjeksiyon noktasına, Traktor sınıfı türünden bir nesnenin enjekte edilmesi isteniyorsa, Galeri ve Traktor sınıflarında aşağıdaki değişiklikler yapılarak sağlanabilir.
@TraktorSecici public class Traktor implements Arac { public String calis() { return "Traktör "+hizSoyle()+" km. hızında çalışıyor.."; } public int hizSoyle(){ return ThreadLocalRandom.current().nextInt(20, 110) ; } }
@TraktorSecici notasyonu, hem talip olunan sınıf başına hem de, Galeri sınıfı içerisindeki enjeksiyon noktasına çift taraflı olarak eklenmelidir.
public class Galeri { @Inject @TraktorSecici private Arac arac; public static void main(String[] args) { Weld weld = new Weld(); WeldContainer konteyner = weld.initialize(); Galeri galeri = konteyner.instance().select(Galeri.class).get(); String mesaj=galeri.arac.calis(); System.out.println("> "+mesaj); } }
Galeri sınıfının bu son haliyle uygulama koşturulduğunda, aşağıdaki gibi bir çıktının alındığı ve seçim probleminin aşıldığı görülür.
Uygulama kodlarına https://github.com/rahmanusta/Weld-SE-2 adresinden erişebilirsiniz.
Tekrar görüşmek dileğiyle.
1 Comment