Java Serialization – Bölüm 2

JAVA’DA SERIALIZATION 2. BÖLÜM
Serialization özelliğini durdurmaİlk dersimizde serialization ile alakalı bazı şeyler öğrendik şimdi biraz daha görelim. Ya eğer biz Serializable yaptığımız bir classtan subclass oluşturduysak, ama bu yeni subclass’ın serializable olmasını istemiyorsak? Siz bu arayüz içinunimplements gibi bir şey yazamazsınız. Yani, eğer sizin super classınız Serializable ise, yeni classınız da bunu uygular. Bu otomatik serialization özelliğini engellemek için, siz private metodlar kullanarak, writeObject ve readObjectmetodlarını override edebilirsiniz. private yaptığınız için, sizden sonra kaynak kodlar elinde olmayan hiç kimse, bu metodları değiştirip serializable yapamaz. İsterseniz subclasslarda tekrar implements Serializable diyerek bu özelliği aktif edebilirsiniz. Neyse, serialization özelliğini kapatmak için yapmanız gereken tek şey,
NotSerializableException fırlatmaktır. Nasıl yapılacağını da yazalım:
private void writeObject(ObjectOutputStream out) throws IOException{
throw new NotSerializableException(“Not today!”);
}
private void readObject(ObjectInputStream in) throws IOException{
throw new NotSerializableException(“Not today!”);
}

Bu classın herhangi bir objesini yazma veya okuma için yapılan her girişim, Exception fırlatılmasıyla sonuçlanır. Hatırlayın, bu metodlar private olduğu için, kimse kaynak kodlar elinde olmadan kodunuzu override edip bunu değiştiremez.._________________
Gelelim bu başlıktaki esas konumuza… Önceki konuyu okumamış olsanız bile, Eclipse gibi bir editör kullandıysanız kafanızı kurcalayan şeylerden birisi de classı tanıttığınız satırdaki uyarı işareti olmuştur.
Hani üzerine gelince şu uyarıyı veren:
The serializable class xxx does not declare a static final serialVersionUID field of type long

Eclipse görüntüsü yukarıdaki gibi olan uyarı…
(Version Kontrolü)

Hayal edin, siz bir class yazdınız, bundan bir obje oluşturup writeObject ile dosyaya yazdınız. Bu serileştirilmiş obje sizin hard diskinizde bir süre durdu. Fakat bu sırada, siz yazdığınız class dosyanıza yeni şeyler eklediniz. Şimdi ne olacak peki? Sizin eskiden dosyaya yazdığınız objeye ulaşmaya çalışacaksınız ama onda classınızın yeni hali için yeterli veri bulunmuyor.(Eksik veri var). Kötü haber şu, bir Exception fırlatılacak — Özel ismiyle, java.io.InvalidClassException — çünkü bütün Serializable classlara otomatik olarak verilen özel bir ayıraç vardır. Eğer sıkıştırılan objenin classı ile geri okunan yerdeki class (bytecode olan “.class” uzantılı elemanlardan bahsediyorum.) karşılaştırıldığında bunların ayıraçları uyuşmuyorsa, exception fırlatılır. Halbuki, düşününce, neden sadece yeni bir değişken yüzünden benim eski objelerime ulaşmam engellensin ki? Neden sadece bir yeni değişken için Exception fırlatılsın ki? Bu yeni değişkeni default olarak bir değere eşitlese olmaz mı?
Cevabımız Evet, ama bu, kodda birazcık düzenleme yapmayı gerektiriyor. Bütün classlarda bulunan, yukarıda bahsettiğimiz ayıraç, serialVersionUID değişkeninde tutulur. Eğer siz versiyon kontrolü yapmak isterseniz, classınıza serialVersionUID değişkenini sağlamak zorundasınız ve bunun ne olursa olsun aynı kalmasını garanti etmelisiniz.

Eee…Nedir bu SerialVersionUID?

serialVersionUID, Serializable objeler için bir sürüm kontrolörüdür.. Eğer siz serialVersionUID değişkeni tanıtmadıysanız, JVM sizin yerinize, birçok farklı şeye bağlı olarak otomatik olarak bir tane oluşturacaktır. (Bunlardan ayrı ayrı bahsetmeyeceğim.)

Bir örnekle etkilerini inceleyelim.



Bu kodda kendimiz “serial version” belirttik. Hatasız bir output alıyoruz:

Şimdi Adres.java’daki serialversionUID değişkenini 2L olarak değiştirelim.

Bu durumda karşılaşacağımız konsol ekranı şöyledir:

Otomatik olarak oluşturulan SerialVersionUID neden iyi değildir?

Eğer serialVersionUID tanıtılmadıysa, JVM kendi algoritmasını kullanarak bir SerialVersionUID oluşturur, buradan ilgili bilgilere ulaşabilirsiniz. varsayılan serialVersionUID oluşturulması, class ve değişken ile ilgili detaylara çok hassastır ve JVM’lere göre bazı farklılıklar olabilir. Bu da siz hatasız bir deserialization olmasını umarken beklenmeyen bir InvalidClassException ile karşılaşmanıza neden olabilir..
Örneğin Client / Server Ortamı

– Client, SUN’ın Windows JVM’ini kullanıyor.
– Server ise Linux’ta JRockit kullanıyor.
Client, sockete varsayılan algoritmayla serialVersionUID oluşturulmuş, serializable bir class (örneğin 123L) gönderiyor. Ama server deserialization sırasında farklı bir serialVersionUID (örneğin 124L) oluşturabilir, ve beklenmeyen bir InvalidClassExceptions ile karşılaşılır..
Aynı şey, Dosya / Veritabanı Ortamı için de geçerlidir. Aynı durumla bu ortamda da karşılaşılabilir.

SerialVersionUID nasıl oluşturulur?

Yukarıdaki kısmı ezberlemeniz gerekmiyor elbette.
JDK’da “serialver” denilen bir özellik var. Bunu kullanabilirsiniz. Ya da Eclipse IDE ‘de class tanıttığınız satırın yanındaki ünleme tıklayarak yapabilrsiniz. Aşağıda daha detaylısı:

serialVersionUID oluşturmak için 3 yol vardır.
1. Serialver Komutu

JDK built-in komuta sahiptir (“serialver”) Bu otomatik olarak serialVersionUID oluşturmaya yarar. Aşağıdaki örnekte, “serialver” serialVersionUID oluşturmak için kullanılmıştır.(Alıntı yaptım =) )
E:\\workspace\\target\\classes>serialver Adres
Adres:    static final long serialVersionUID = -687991492884005033L;

Bu satırı kopyalayın ve kodunuza yapıştırın.
2. Eclispe IDE için

Eclipse zaten size çözüm yöntemlerini söylüyor.
3. İstediğiniz herhangi bir sayı

Kendi istediğiniz sayıyı serialVersionUID ‘ye atayın, Bir sayı seçip sonuna “L” harfini ekleyin yeter. Türünü long yapmayı da unutmayın.

private static final long serialVersionUID = 1L;

Sonuç Olarak:

serialVersionUID’nin kendinizin belirlediği bir değer olması özellikle tavsiye ediliyor. Yukarıda bahsettiğim problemlerden ötürü, ben de kullanacağınızda kesinlikle böyle kullanmanızı öneriyorum. Kullanmadan önce serialization ’ın hangi işlerde kullanılabileceğini ve özelliklerini iyice öğrenmelisiniz diyorum.

Serialization ile neler yapabileceğinizi hayal edebilmeniz için küçük bir ipucu söyleyeyim. Mesela, ArrayList objesi Serializable bir objedir. Yani siz bir veritabanınızı Obje olarak dosyada tutabilirsiniz. Bu sayede üçüncü kişilerin, sahip olduğunuz veritabanını çözemeyecekleri bir şifreleme ile şifrelemiş olursunuz.

Leave a comment