<-- home

JSF Validator'larında Dependency Injection (ayrıca Spring ile)

Acayip bir dil in, Türkçe yine out. Dependency Injection’ı herkes kafasına göre Türkçeye çevirmiş ama bence en güzel ve geçerlisi şu abimin dediği “bağımlılık zerketme”.

Efenim JSF bize bean’lerimiz içerisinde validator metodlar tanımlama imkanı sunuyor olsa da, duruma özel validator’ları yeniden kullanılabilirlik açısından ayrı sınıflar halinde yazmak bence daha makul. Örneğin bir üye kayıt formunda kullanıcının girdiği eposta adresinin başka birisi tarafından kullanılıyor olup olmadığının kontrolünü formun arkasındaki bean üzerinden ya da ayrı bir (custom) validator üzerinden yapabiliriz. Bu kontrol bize yalnızca üye kayıt esnasında gerekiyorsa bean içinde tanımlamak uygun olabilir, bean ayrıca JSF tarafından yönetildiğinden, asıl sorguyu yapacağımız sınıfı JSF bize inject edecektir ve doğrudan sorgumuzu yapıp işi halledebiliriz. Ama örneğin başka bir kaç noktada daha verilen bir eposta adresinin veritabanında kayıtlı olup olmadığının kontrolü gerekebilir. Bu durumda, işlemi bir (custom) validator sınıfa koymak kod tekrarı yapmamak ve bu sınıfı gerektiği noktalarda kullanabilmek açısından gayet mantıklı.

Ama burda da şöyle bir durumla karşılaşıyoruz. Validator ve PhaseListener’larda JSF bize Dependeny Injection güzelliği sağlamıyor. Biz validator içinde eposta kontrolünü UserService.checkEmailExists() gibi bir metod üzerinden yapacaksak, o UserService referansını bize JSF inject etmiyor.

Yahut validator içerisinde SessionScope’da yer alan bir bean’ın içerdiği bir değeri kullanmamız gerekebilir ve o bean’e erişmek isteyebilirdik. ManagedBean içerisinde olsaydık, @ManagedProperty diyerek ihtiyaç duyduğumuz bean’in JSF tarafından bize verilmesini sağlayabilirdik, ama dediğim gibi validator içinde böyle bir şansımız yok.

E o zaman ne yapacağız? JSF’in yaptığı Dependency Injection güzelliğini, biz programatik olarak yapacağız.

Şu kod parçası, bize, erişmek istediğimiz bean’i getiriyor.

ELContext elContext = FacesContext.getCurrentInstance().getELContext();
MyBean myBean = (MyBean) FacesContext.getCurrentInstance()
		.getApplication().getELResolver()
		.getValue(elContext, null, "myBean");

Örneğin bizim yukarıda bahsettiğimiz UserService, ApplicationScope (SessionScope vs de olabilir) bir bean olsaydı, bu kod ile onu elde edip, veritabanındaki kontrolü ona yaptırabilirdik.

Peki JSF ile birlikte Spring de kullanıyorsak ve bizim UserService’in yaşam döngüsünü Spring yönetiyorsa? UserService’e erişmek için yine aynı mantığı kullanacak, bu kez UserService’i Spring’in container’ından isteyecektik. Onu da şöyle yapıyoruz:

ServletContext servletContext = (ServletContext) FacesContext
				.getCurrentInstance().getExternalContext().getContext();

WebApplicationContext wac = WebApplicationContextUtils
				.getRequiredWebApplicationContext(servletContext);

UserService userService = (UserService) wac.getBean("userService");

Bu kod ile, önce ServletContext’e, onun üzerinden Spring Container’ına, onun üzerinden de bize lazım olan gerçekleştirime ulaştık.

JSF’e de, Validator ve PhaseListener’larda Dependency Injection yapmadığı için çok kırıldım, onlar üvey evlat mı?