Vinnie’nin Mutfağından : Vekil sınıflar java.lang.reflect.Proxy
j2ee, java September 12th, 2007
Selamlar, bugün mutfağımızda Vekil sınıfları inceleyeceğiz. Vekil sınıfları “dinamik olarak istenen arayüzleri gerçekleştirmiş olarak oluşturabilir sınıflar” olarak tanımlayabiliriz.
Bu basit programlarda anlamsız görünebilir “Kendim yazacağım programı neden dinamik oluşturmaya çalışayım” diyebilirsiniz ama bu şu anki tüm uygulama sunucularının olmazsa olmaz çalışma mantığı.
O yüzden bugün mutfağımızda bir JEE server yazacağız(Oha!). Yazacağımız kısım tabii ki sadece küçük bir kısım, o da database’den bir kayıdı java çekirdeği olarak alan bir entitymanager yani varlıkyöneticisi.
Önce sunucu tarafını yazmaya başlayalım, sunucu kendisine verilen bir arayüz ve kriter ile kurduğu bağlantıda bir veritabanı kaydı arayacak ve bunu döndürecek. Örnek olması açısından tablonun primary key alanının adının “id” olması ve diğer alanların küçük harf olması gerekiyor.
public class Server {
private java.sql.Connection con;
private class ResultSetInvocationHandlerImpl
implements java.lang.reflect.InvocationHandler {
private java.sql.ResultSet rs;
public ResultSetInvocationHandlerImpl(java.sql.ResultSet rsval) {
this.rs = rsval;
}
@Override public Object invoke(Object proxy,
java.lang.reflect.Method method, Object[] args) throws Throwable {
String label = method.getName().substring(3)
.toLowerCase(java.util.Locale.ENGLISH);
return this.rs.getObject(label);
}
}
public Server() throws Exception{
Class.forName("com.mysql.jdbc.Driver");
this.con = java.sql.DriverManager
.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
}
public <T> T varlikBul(Class<T> iface, Object id) throws Exception{
java.sql.PreparedStatement ps = this.con.prepareStatement(
"SELECT * FROM " + iface.getName() + " where id=?");
ps.setObject(1, id);
java.sql.ResultSet rs = ps.executeQuery();
rs.next();
T t = (T) java.lang.reflect.Proxy.newProxyInstance(
iface.getClassLoader(),
new Class[]{iface},
new ResultSetInvocationHandlerImpl(rs));
return t;
}
}
Server sınıfımız bir iç sınıfa sahip bu üretilen vekil sınıfa yapılan çağrıları karşılayacak olan sınıf. Gerçeklemesi gereken tek metod var. Bu “invoke” metodu, proxy yani vekil sınıf, çağrılan metod ve argümanları almalı ve buna yapıcı metodunda verilen sonuç setine göre cevap üretmeli.
Bir sunucuda olması gerektiği gibi bir veritabanı bağlantısı taşıyor ve kendisinden bir varlık istendiğinde id ile sorgulamasını yapıyor ve oluşturduğu vekili istemcisine döndürüyor. İşe bu kadar.
Gelelim istemci tarafına. Sunucu için bu kadar uğraştıktan sonra istemci kısmı kolay. Bu kodu tek bir dosya içine yazabilirsiniz:
interface TestEntity {
public Integer getId();
public String getName();
public Integer getVersion();
}
public class CompileTest {
public static void main(String[] args) throws Exception {
TestEntity te = new Server().varlikBul(TestEntity.class, 1);
System.out.println(te.getId());
System.out.println(te.getName());
System.out.println(te.getVersion());
}
}
Veritabanındaki tablo ile aynı isimde bir arayüz yarattık, “getter” metodlarını yazdık ve sunucudan bu kaydı istedik.
Son olarak bir konuda uyarmak istiyorum. Dikkat edilirse vekil sınıfında kolon değerini getObject ile alıyoruz ve döndürüyoruz, bu dönürülen nesne veritabanındaki int bir alan için Integer dönürmeli. Bazı sürücülerde bu davranış farklı olabilir. Eğer sürücü java.lang.Long döndürürse ClassCastException almamız işten bile değil. Tabi bu sadece bir örnek, iyi bir kodlama için bağlantıları kapatmalı ve her türlü durumu karşılayacak hata denetimleri yapmalıyız.
Bugün mutfağımızda bir EntityManager benzeri bir yapı kurduk. Hepimize afiyet olsun.
Vinnie
Social Bookmarking