Tuesday, September 28, 2010

java.io.Serializable

Java tamamen nesne yönelimli bir programlama dili olduğu için, Java üzerinde uygulama geliştirirken nesneleri sıkça kullanıyoruz. Java platformunda bilindiği gibi, int, double, byte gibi primitive tipler dışındaki herşey nesnedir.

Ancak Java’da kullanılan nesneler, Java platformunda (JVM) hayat bulurlar. Platform dışında nesnelerin, hiçbir anlamı yoktur. Nesne yönelimli programlama paradigmasını destekleyen Java’da, tasarlanan nesnelerin tekrar kullanılabilmesi (reuse) önemli bir konu olduğuna göre, bu nesneleri Java platformu dışında da hayata geçirmek gerçekten önemlidir. Bahsedilen bu problem, Java Serialization API sayesinde çok kolay bir şekilde aşılabiliyor.

Konuya bir de şu yönden bakarsak, herhangi bir nesne içerisindeki fieldları bir dosyaya yazdırdığımızda, bu verilerin sadece değerlerini (values) dosya içerisinde depolarız. Halbuki bu verilerin sınıf tanımlaması içerisindeki tipleri de en az değerleri kadar önemlidir. Herhangi bir nesnenin fieldındaki değer 3 ise, bu değerin string mi int mi olduğunun dosya üzerinde bir anlamı yoktur.

Java Serialization API sayesinde bir nesnenin birebir kopyasını, Java platformu dışında da depolayabiliriz. Bu mekanizma ile daha sonra, nesneyi depolanan yerden çekip, aynı durum (state) ve özellikleri ile kullanmaya devam edebiliriz. Tüm bu sisteme, Object Serialization (Nesne Serileştirme) adı verilir.

Object Serialization Temelleri

Nesneleri serileştirmek için yapılması gereken tek şey, serileştirilecek nesnemizin serileştirilebilir (serializable) olduğunu tagging interface sayesinde sınıf deklarasyonunun başında belirtmek.

Peki, tagging interface tam olarak nedir? Tagging Interface, basit bir Java interfaceidir. Özelliği, içerisinde herhangi bir method tanımlaması yapmaz. Sadece belirli işlerin, belirli nesneler tarafından yapılabilmesi için sınıflara bazı standartlar oluşturmak için tasarlanmıştır. Nesne serileştirme işleminde de yapmamız gereken tek şey Serializable adındaki tagging interface i, serileştirilecek olan nesnenin sınıf deklarasyonunda ya da kalıtım ile türediği sınıfın bu interfacei uygulaması gerekmektedir. (implement edilmesi)

Nesneleri serileştirmek için Java platformu 2 temel sınıf sunar. ObjectInputStream ve ObjectOutputStream adı verilen bu iki sınıf ile, Serializable interfaceini uygulayan herhangi bir sınıfı serileştirebiliriz. Bu iki sınıfdan ilki olan ObjectInputStream, ObjectInput interfaceini uygular ve serileştrilen nesneyi tekrar akışdan okumak için kullanılır. ObjectInputStream adındaki diğer sınıf, ObjectOutput interfaceini uygular ve herhangi bir nesneyi akışa yazdırmak için kullanılır.

ObjectInput interfacei, readObject adında bir method sunar ve serileştirilen nesneyi akışdan okumak için kullanılır. Yine aynı şekilde ObjectOutput interfacei, writeObject adında bir method sunar ve bu method sayesinde Serializable interfaceini uygulayan herhangi bir nesneyi herhangi bir akışa yazdırabiliriz. Bu iki interfacei sırasıyla uygulayan ObjectInputStream ve ObjectOutputStream sınıfları bu methodları kendi içinde tanımlayarak, kullanıma hazırlar.

Bu iki sınıfı kullanmak çok basittir. Serileştirilecek ve geri çekilecek nesneler eğer dosyalar üzerinde yapılacaksa, bu iki sınıfa dosyaya yazdırmak için java.io paketince sunulan FileInputStream veya FileOutputStream nesnelerini geçirmek yeterlidir.


NonSerializable Objects

Buraya kadar nesnelerin neden serileştirilmesi gerektiğini ve bunlar için hangi adımları takip etmemiz gerektiğinden bahsettik. Serializable arayüzünü uygulayan bir sınıfın tüm nesneleri serileştirilebilirdir. Ancak, eğer sınıf içerisindeki değişkenlerin tamamı primitive tip ise sorun yok, çünkü tüm primitive tipler otomatik olarak serileştirilebilir. Ama, sınıf içerisinde referans tipde değişkenler (reference type variables) var ise, bu değişkenlerin tuttuğu nesne örneklerinin serileştirilebilir (Serializable) olduğunu sınıf tanımlamasından tespit etmelisiniz. Çünkü tüm nesnelerin türediği java.lang.Object sınıfı Serializable interfaceini uygulamaz. Örnek olarak String nesneleri Java da öntanımlı olarak Serializable interfaceini tanımlar.

Burda bahsetmem gereken bir diğer nokta da, serileştirilme işleminin yapılmasını istemediğiniz sınıf alanları varsa (fields) bunları transient olarak sınıf tanımlamasında belirtmemiz gerekiyor. Eğer, herhangi bir sınıf içinde javaBlog adında bir field var ve siz bu fieldı serileştirilme işleminden hariç tutmak istiyor iseniz, şu şekilde tanımlamanız gerekiyor.
transient private JavaBlog javaBlog;

Örnek Kod

import java.io.Serializable;
public class Data implements Serializable{
        private String name;
        private String surname;
        private int age;
 
         public Data(String name, String surname, int age) {
                  this.name = name;
                  this.surname = surname;
                  this.age = age;
         }

          public int getAge() {
                  return age;
           }

           public String getName() {
                   return name;
            }

            public String getSurname() {
                    return surname;
             }
}




public class Main {
        public static void main(String[] args) {
               try {
                    Data d1 = new Data("Abdulkadir", "Selcukoglu", 27);
                    File f = new File("c:\\data.out");
                    f.createNewFile();
                    FileOutputStream fOut = new FileOutputStream(f);
                    ObjectOutputStream out = new ObjectOutputStream(fOut);
                    out.writeObject(d1);
                    out.close();
                    System.out.println("Process ends...");
              } catch (Exception e) {
                      System.out.println("Error in serializtion process!\n");
                      e.printStackTrace();
              }
       }
}

//Console Output
Process ends...


public class Main {
       public static void main(String[] args) {
               try {
                      Data d; //Nesnemizi tanımladık
                      File f = new File("c:\\data.out");
                      FileInputStream fIn = new FileInputStream(f); //Dosyamızı okumak üzere açtık
                      ObjectInputStream in = new ObjectInputStream(fIn); //Nesnemizi okuyacak olan                                                                                                                         //sınıfın örneğini oluşturduk
                      d = (Data) in.readObject(); //nesnemize okuduğumuz nesneyi atadık
                      System.out.println("DATA OF OBJECT");
                      System.out.println(d.getName() + " " + d.getSurname() + " " + d.getAge());                                        System.out.println("Process ends...");
               } catch (Exception e) {
                      System.out.println("Error in serializtion process!\n");
                      e.printStackTrace();
               }
        }
}


//Console Output
 DATA OF OBJECT
Abdulkadir Selcukoglu 27
Process ends...


ObjectOutputStream and ObjectInputStream

public class Cat implements Serializable {    
 
}
 
public class SerializeCat {
        public static void main(String[] args) {
               Cat c = new Cat();
                try {
                       FileOutputStream fs = new FileOutputStream("testSer.ser");
                       ObjectOutputStream os = new ObjectOutputStream(fs);
                        os.writeObject(c); // 3
                        os.close();
                } catch (Exception e) {
                        e.printStackTrace();
                }
                try {
                        FileInputStream fis = new FileInputStream("testSer.ser");
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        c = (Cat) ois.readObject(); // 4
                        ois.close();
                } catch (Exception e) {
                        e.printStackTrace();
                }
       }
}

//Console Output 
 

Simdide biraz bu konuyla uygulama yaparak neler yapabilecegimize bakalim 

Object Graphs
  
public class Collar implements Serializable{
        private String collar;
        public Collar(String collar) {
              this.collar = collar;
        }

        public String getCollar() {
              return collar;
        }
}

 

public class Dog implements Serializable {
       private Collar dogCollar;
       private String dogName;

       public Dog(Collar dogCollar, String dogName) {
              this.dogCollar = dogCollar;
              this.dogName = dogName;
       }

       public Collar getDogCollar() {
             return dogCollar;
       }

       public String getDogName() {
             return dogName;
       }
}


public class SerializeDog {
        public static void main(String[] args) {
                Collar c = new Collar("Black");
                Dog d = new Dog(c, "Karabas");
                System.out.println("before: collar : " + d.getDogCollar().getCollar() + "name : "+d.getDogName());
                try {
                        FileOutputStream fs = new FileOutputStream("testSer.ser");
                        ObjectOutputStream os = new ObjectOutputStream(fs);
                        os.writeObject(d);
                        os.close();
                } catch (Exception e) {
                         e.printStackTrace();
                }
                try {
                        FileInputStream fis = new FileInputStream("testSer.ser");
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        d = (Dog) ois.readObject();
                        ois.close();
                } catch (Exception e) {
                         e.printStackTrace();
                }
                System.out.println("after: collar : " + d.getDogCollar().getCollar() + "name : "+d.getDogName());
       }
}

//Console Outout
 before: collar : Blackname : Karabas
after: collar : Blackname : Karabas



Goruldugu gibi veri butunlugu saglanaraktan yazildi ve yine oldugu yerden veri butunlugu korunaraktan alindi. Simdi bir uygulama daha yapalim ve Collar sinifini  Serializable yapmadan nasil islem yapabiliriz ona bakalim.



Using writeObject and readObject


public class Collar{
        private String collar;
        public Collar(String collar) {
              this.collar = collar;
        }

        public String getCollar() {
              return collar;
        }
}

 

public class Dog implements Serializable {
       private transient Collar dogCollar;
       private String dogName;

       public Dog(Collar dogCollar, String dogName) {
              this.dogCollar = dogCollar;
              this.dogName = dogName;
       }

       public Collar getDogCollar() {
             return dogCollar;
       }

       public String getDogName() {
             return dogName;
       }
}


public class SerializeDog {
        public static void main(String[] args) {
                Collar c = new Collar("Black");
                Dog d = new Dog(c, "Karabas");
                System.out.println("before: collar : " + d.getDogCollar().getCollar() + "name : "+d.getDogName());
                try {
                        FileOutputStream fs = new FileOutputStream("testSer.ser");
                        ObjectOutputStream os = new ObjectOutputStream(fs);
                        os.writeObject(d);
                        os.close();
                } catch (Exception e) {
                         e.printStackTrace();
                }
                try {
                        FileInputStream fis = new FileInputStream("testSer.ser");
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        d = (Dog) ois.readObject();
                        ois.close();
                } catch (Exception e) {
                         e.printStackTrace();
                }
                System.out.println("after: collar : " + d.getDogCollar().getCollar() + "name : "+d.getDogName());
       }
}



//Console Output
before: collar : Blackname : Karabas
Exception in thread "main" java.lang.NullPointerException
at transientdemo.hatalihali.SerializeDog.main(SerializeDog.java:38)
Java Result: 1

 


Bu hatanin sebebi Collar'in  Serializable olmamasi bunida su sekilde halledebiliriz simdi asagida duzgun calisan seklini yapiyoz



public class Collar{
        private String collar;
        public Collar(String collar) {
              this.collar = collar;
        }

        public String getCollar() {
              return collar;
        }
}

 

public class Dog implements Serializable {
       private transient Collar dogCollar;
       private String dogName;

       public Dog(Collar dogCollar, String dogName) {
              this.dogCollar = dogCollar;
              this.dogName = dogName;
       }

       public Collar getDogCollar() {
             return dogCollar;
       }

       public String getDogName() {
             return dogName;
       }

       private void writeObject(ObjectOutputStream os) {
              try {
                     os.defaultWriteObject();
                     os.writeObject(dogCollar.getCollar());
             } catch (Exception e) {

                    e.printStackTrace();
             }
       }

       private void readObject(ObjectInputStream is) {
             try {
                    is.defaultReadObject();
                    dogCollar = new Collar(is.readObject().toString());
             } catch (Exception e) {
                    e.printStackTrace();
             }
       }
 
}


public class SerializeDog {
        public static void main(String[] args) {
                Collar c = new Collar("Black");
                Dog d = new Dog(c, "Karabas");
                System.out.println("before: collar : " + d.getDogCollar().getCollar() + "name : "+d.getDogName());
                try {
                        FileOutputStream fs = new FileOutputStream("testSer.ser");
                        ObjectOutputStream os = new ObjectOutputStream(fs);
                        os.writeObject(d);
                        os.close();
                } catch (Exception e) {
                         e.printStackTrace();
                }
                try {
                        FileInputStream fis = new FileInputStream("testSer.ser");
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        d = (Dog) ois.readObject();
                        ois.close();
                } catch (Exception e) {
                         e.printStackTrace();
                }
                System.out.println("after: collar : " + d.getDogCollar().getCollar() + "name : "+d.getDogName());
       }
}


//Console Output
 before: collar : Blackname : Karabas
after: collar : Blackname : Karabas




How Inheritance Affects Serialization
Simdide farkli bir detaya deginelim peki ya superclass

public class Animal{
        int weight = 42;
}


public class Dog extends Animal implements java.io.Serializable{
         String name;
         public Dog(int weight , String name) {
               this.name = name;
               this.weight = weight;
         }

}
 


public class TestMain {
      public static void main(String[] args) {
              Dog d = new Dog(35, "Fido");
              System.out.println("before: " + d.name + " "+ d.weight);
               try {
                        FileOutputStream fs = new FileOutputStream("testSer.ser");
                        ObjectOutputStream os = new ObjectOutputStream(fs);
                         os.writeObject(d);
                         os.close();
               } catch (Exception e) {
                          e.printStackTrace();
               }
               try {
                        FileInputStream fis = new FileInputStream("testSer.ser");
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        d = (Dog) ois.readObject();
                        ois.close();
               } catch (Exception e) {
                        e.printStackTrace();
               }
               System.out.println("after: " + d.name + " "+ d.weight);
     }
}

//Console Output
before: Fido 35
after: Fido 42


Gorulduyu uzer veri butunlugu korunamadi cunku veri butunlu korunmasi icin Animal sinifininda .Serializable implements etmeliydi yani su sekilde olunca istenilen sekilde calismis oluyor

public class Animal implements Serializable {
        int weight = 42;
}


public class Dog extends Animal implements Serializable{
         String name;
         public Dog(int weight , String name) {
               this.name = name;
               this.weight = weight;
         }

}
 


public class TestMain {
      public static void main(String[] args) {
              Dog d = new Dog(35, "Fido");
              System.out.println("before: " + d.name + " "+ d.weight);
               try {
                        FileOutputStream fs = new FileOutputStream("testSer.ser");
                        ObjectOutputStream os = new ObjectOutputStream(fs);
                         os.writeObject(d);
                         os.close();
               } catch (Exception e) {
                          e.printStackTrace();
               }
               try {
                        FileInputStream fis = new FileInputStream("testSer.ser");
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        d = (Dog) ois.readObject();
                        ois.close();
               } catch (Exception e) {
                        e.printStackTrace();
               }
               System.out.println("after: " + d.name + " "+ d.weight);
     }
}

//Console Output
before: Fido 35
after: Fido 35


Gorulduyu gibi bilgi butunlugu bozulmadan islem tamamlandi...

 Bu yazilanlar tamamen alintidir. Asagidaki iki siteden alinti yapilmistir. Yazan hocalarimin elerine saglik bilgilerini paylastigi icin Allah razi olsun
http://www.javablog.org/55-java-object-serialization
http://www.csharpnedir.com/articles/read/?id=518

No comments:

Post a Comment