Java Objects Serializing/Deserializing - ලංකාවේ S/W Engineers ලට

Java Objects Serializing/Deserializing - ලංකාවේ S/W Engineers ලට

ආයුබෝවන් කට්ටිය! කොහොමද ඉතින්? අද අපි කතා කරන්න යන්නේ Java වල ගොඩක් වැදගත් ඒ වගේම ප්‍රායෝගික වැඩවලදී නැතුවම බැරි concept එකක් ගැන – ඒ තමයි Serialization සහ Deserialization. "Serialization? Deserialization? ඒ මොනවද බං?" කියලා හිතෙනවනම්, බය වෙන්න එපා! අපි මේක ලේසිම ලේසි විදියට, අපේම විදියට කතා කරමු. මොකද මේක හරියට, ඔයාගේ පොත් පත්, බඩු බාහිරාදිය ඔක්කොම පෙට්ටියකට දාලා, ඕන තැනකට ගෙනිහින්, ආපහු unpack කරනවා වගේ වැඩක්!

S/W Engineers විදියට අපිට, program එකක තියෙන data, එහෙම නැත්නම් Java objects, file එකක save කරගන්න, එහෙමත් නැත්නම් network එකක් හරහා වෙන computer එකකට යවන්න, ආයෙත් ඒ object එක අපේ program එකට ගෙන්න ගන්න ඕන වෙනවා. අන්න ඒ වගේ වෙලාවට තමයි මේ Serialization සහ Deserialization අපිට උදව් වෙන්නේ. අපි බලමු එහෙනම් මේක හරියටම මොකක්ද කියලා.

Serialization කියන්නේ මොකක්ද?

සරලවම කිව්වොත්, Serialization කියන්නේ Java object එකක්, byte stream එකක් බවට පත් කරන එක. Byte stream එකක් කියන්නේ මොකක්ද? ඒක හරියට අපි file එකක දත්ත store කරන විදියට, එහෙමත් නැත්නම් network එකක් හරහා data යවන විදියට, binary format එකට convert කරනවා වගේ වැඩක්. ඇයි අපි මෙහෙම කරන්නේ? මොකද Java object එකක් කියන්නේ, memory එකේ තියෙන, program එක run වෙන වෙලාවට විතරක් තියෙන දෙයක්. ඒක අපිට, program එක shut down කරලත් තියාගන්න ඕන නම්, එහෙමත් නැත්නම් වෙන program එකකට, නැත්නම් වෙන server එකකට යවන්න ඕන නම්, මේ byte stream එකක් විදියට convert කරන එක අනිවාර්යයි. මේ process එකට object serialization කියලත් කියනවා.

Java වලදී මේ වැඩේට අපිට ගොඩක්ම උදව් වෙන්නේ java.io.Serializable interface එක. පුදුම වෙන්න එපා! මේක special interface එකක්. මේකට කිසිම method එකක් නෑ. මේක අපි object එක serializable කරන්න ඕන class එකට implement කරාම, Java Runtime එකට කියනවා "මගේ මේ object එක serializable කරන්න පුළුවන්!" කියලා. ඒක හරියට පොඩි marking එකක් වගේ. ඊට පස්සේ Java ගේ default serialization mechanism එකට පුළුවන් ඒ object එක byte stream එකක් බවට convert කරන්න.

දැන් අපි පොඩි code example එකකින් මේක බලමු. අපි Student කියලා class එකක් හදමු.

import java.io.Serializable;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;

class Student implements Serializable {
    private String name;
    private int age;
    private transient String secretInfo; // transient keyword එක ගැන පස්සේ කතා කරමු

    public Student(String name, int age, String secretInfo) {
        this.name = name;
        this.age = age;
        this.secretInfo = secretInfo;
    }

    // Getters for demonstration
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getSecretInfo() {
        return secretInfo;
    }

    @Override
    public String toString() {
        return "Student{" +
               "name='" + name + '\'' +
               ", age=" + age +
               ", secretInfo='" + secretInfo + '\'' +
               '}';
    }
}

public class SerializationDemo {
    public static void main(String[] args) {
        Student student = new Student("Nimal Perera", 23, "TopSecret!");
        String filename = "student.ser"; // .ser කියන්නේ serializable files වලට දෙන සාමාන්‍ය extension එකක්

        try {
            // Object එක file එකකට ලියන්න stream එකක් හදනවා
            FileOutputStream fileOut = new FileOutputStream(filename);
            ObjectOutputStream out = new ObjectOutputStream(fileOut);

            // Object එක serialize කරනවා
            out.writeObject(student);

            out.close();
            fileOut.close();
            System.out.println("Student object serialized and saved to " + filename);
            System.out.println("Original object: " + student);

        } catch (IOException i) {
            i.printStackTrace();
        }
    }
}

මේ code එක run කරාම, student.ser කියලා binary file එකක් හැදෙනවා. ඒක ඇතුලේ තමයි අපේ Student object එකේ data, byte stream එකක් විදියට තියෙන්නේ. ඒ file එක නිකං open කරලා බැලුවොත්, ඔයාට තේරෙන්නේ නැති අමුතු symbols ටිකක් පෙනේවි. ඒක සාමාන්‍ය දෙයක්, මොකද ඒක binary format එකකින් තියෙන්නේ.

Deserialization කියන්නේ මොකක්ද?

හරි, දැන් අපි object එකක් byte stream එකක් විදියට save කරගත්තා. Deserialization කියන්නේ, ඒ byte stream එක ආපහු original Java object එකට convert කරන එක. මේක හරියට අපි කලින් පෙට්ටියට දාපු බඩු, ආපහු එලියට අරගෙන, තිබ්බ විදියටම unpack කරනවා වගේ වැඩක්. අපි කලින් serialize කරපු Student object එක, student.ser file එකෙන් ආපහු read කරලා, original Student object එක විදියටම ලබා ගන්නේ කොහොමද කියලා බලමු.

මේ වැඩේට අපිට ObjectInputStream කියන class එක උදව් වෙනවා. ඒකෙන් අපි byte stream එක read කරලා, readObject() method එක පාවිච්චි කරලා object එක නැවත ලබා ගන්නවා.

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.lang.ClassNotFoundException; // Deserialization වලදී මේ exception එක එන්න පුළුවන්

public class DeserializationDemo {
    public static void main(String[] args) {
        Student student = null;
        String filename = "student.ser";

        try {
            // File එකෙන් object එක කියවන්න stream එකක් හදනවා
            FileInputStream fileIn = new FileInputStream(filename);
            ObjectInputStream in = new ObjectInputStream(fileIn);

            // Object එක deserialize කරනවා. Object එක cast කරන්න ඕන
            student = (Student) in.readObject();

            in.close();
            fileIn.close();
            System.out.println("Student object deserialized from " + filename);
            System.out.println("Deserialized object: " + student);
            System.out.println("Name: " + student.getName());
            System.out.println("Age: " + student.getAge());
            System.out.println("Secret Info: " + student.getSecretInfo()); // transient නිසා null වෙයි

        } catch (IOException i) {
            i.printStackTrace();
            return;
        } catch (ClassNotFoundException c) {
            System.out.println("Student class not found.");
            c.printStackTrace();
            return;
        }
    }
}

මේ code එක run කරාම, ඔයාට පෙනේවි student.ser file එකෙන් read කරපු Student object එක, කලින් තිබ්බ විදියටම data එක්ක ලැබෙනවා. හැබැයි අපි බලමු secretInfo field එකට මොකද වෙන්නේ කියලා. ඒක null වෙලා තියෙන්නේ නේද? අන්න ඒකට තමයි transient keyword එක පාවිච්චි කරන්නේ. අපි ඒ ගැන ඊළඟට කතා කරමු.

transient Keyword එකේ වැඩේ

අපි සමහර වෙලාවට object එකක තියෙන හැම field එකක්ම serialize කරන්න ඕන වෙන්නේ නෑ. උදාහරණයක් විදියට, credit card numbers, passwords වගේ sensitive data, එහෙමත් නැත්නම් calculate කරලා ගන්න data (අපි ඒක save කරන්න ඕන නෑ, program එක run වෙනකොට calculate කරන්න පුළුවන්) serialization එකෙන් skip කරන්න ඕන වෙනවා. අන්න ඒ වගේ වෙලාවට අපිට transient කියන keyword එක පාවිච්චි කරන්න පුළුවන්.

transient කියලා field එකක් declare කරාම, Java ගේ default serialization mechanism එක ඒ field එක serialize කරන්නේ නෑ. ඒ කියන්නේ, object එක serialize කරලා, ආපහු deserialize කරනකොට, transient කියලා declare කරපු field එකේ default value එක (primitive types නම් 0, false, null; object types නම් null) ලැබෙනවා. අපි කලින් Student class එකේ secretInfo field එකට transient කියලා දැම්මා නේද? ඒ නිසා තමයි Deserialization කරාම ඒක null වුනේ. මේක security එකටයි, අනවශ්‍ය data save වෙන එක වළක්වා ගන්නයි ගොඩක් වැදගත්.

// Student class එකේ,
// private transient String secretInfo;
// කියලා තියෙන නිසා, මේ field එක serialize වෙන්නේ නෑ.
// Deserialization කරාම, secretInfo එක null විදියට ලැබෙනවා.

මේක හරියට, ඔයාගේ පොතේ තියෙන රහස් පිටුවක්, පොත පෙට්ටියට දානකොට අයින් කරලා, ආපහු unpack කරනකොට ඒ පිටුව අතුරුදහන් වෙලා වගේ වැඩක්. වැදගත් දේවල් ආරක්ෂා කරගන්න මේක මරු ක්‍රමයක්!

Custom Serialization කරන හැටි (Externalizable එක්ක)

හරි, දැන් අපි default serialization ගැන දන්නවා. හැබැයි සමහර වෙලාවට අපිට මේ default mechanism එකෙන් වැඩේ ගොඩ දාගන්න බෑ. අපිට object එක serialize වෙන විදිය ගැන, Deserialization වෙන විදිය ගැන තව වැඩි control එකක් ඕන වෙනවා. උදාහරණයක් විදියට, අපි data compress කරන්න ඕන නම්, එහෙමත් නැත්නම් data encrypt කරන්න ඕන නම්, නැත්නම් වෙනම file format එකකට save කරන්න ඕන නම්, මේ Externalizable interface එක අපිට උදව් වෙනවා.

Serializable වගේ නෙවෙයි, Externalizable interface එකේ methods දෙකක් තියෙනවා – writeExternal(ObjectOutput out) සහ readExternal(ObjectInput in). අපි මේ methods දෙක implement කරන්න ඕන, අපිට ඕන විදියට object එකේ data ලියන්නයි, කියවන්නයි. මේක Serializable එකට වඩා සංකීර්ණයි, හැබැයි performance wise ගොඩක් වාසිදායක වෙන්න පුළුවන්, වගේම අපිට data format එක ගැන සම්පූර්ණ control එකක් දෙනවා.

මේක අර කලින් පෙට්ටියට බඩු දාන කතාවෙන්ම කියනවා නම්, Serializable කියන්නේ, "මේ පෙට්ටිය මට දෙන්න, මම බඩු ටික දාන්නම්" කියනවා වගේ. හැබැයි Externalizable කියන්නේ, "පෙට්ටිය මට දෙන්න, මම මට ඕන විදියට මේ බඩු ටික organize කරලා දාගන්නම්" කියලා කියනවා වගේ. මේක advanced topic එකක්. අදට අපි Serializable එකේ මූලික දේවල් හොඳටම අවබෝධ කරගමු, ඒක තමයි වැඩ ගොඩකට ප්‍රමාණවත්.

Serialization එකේ තියෙන පොඩි පොඩි Issues

Serialization කියන්නේ හෙනම වැදගත් concept එකක් වුනාට, ඒකේ පොඩි පොඩි අවුල් ටිකකුත් තියෙනවා. අපි ඒ ගැනත් පොඩ්ඩක් කතා කරමු.

  1. serialVersionUID එකේ වැදගත්කම: අපි Serializable implement කරන class වල private static final long serialVersionUID = 1L; වගේ එකක් දකිනවා. මේක වැදගත් වෙන්නේ, අපි serialize කරපු object එකක්, පස්සේ ඒ class එකේ structure එක වෙනස් කරලා තියෙනවා නම්, Deserialization කරනකොට error එන එක වළක්වා ගන්න. Class එකේ structure එක (fields අලුතින් add කරාම, remove කරාම වගේ) වෙනස් වෙනකොට, මේ serialVersionUID එකත් update කරන්න ඕන. නැත්නම් InvalidClassException එකක් එන්න පුළුවන්. ඒක හරියට, ඔයා පොතක් serialize කරලා, ඒ පොතේ පිටු ගලවලා, අලුතින් දාලා, ආයෙත් deserialize කරන්න හැදුවොත්, ඒක පොඩ්ඩක් අවුල් යනවා වගේ.
  2. Security Concerns: Serialization කියන්නේ පහසු ක්‍රමයක් වුනත්, security ගැන හිතනකොට පොඩ්ඩක් පරිස්සම් වෙන්න ඕන. Malicious data deserialize කරනකොට, program එකේ security holes ඇති වෙන්න පුළුවන්. ඒ නිසා, unknown sources වලින් එන serialized objects deserialize කරනකොට පරිස්සම් වෙන්න ඕන.
  3. Performance: ලොකු objects serialize කරනකොට, එහෙමත් නැත්නම් ගොඩක් objects serialize කරනකොට, performance එකට බලපෑමක් වෙන්න පුළුවන්. ඒ වගේ වෙලාවට JSON, XML වගේ වෙන data interchange formats පාවිච්චි කරන එක, එහෙමත් නැත්නම් Externalizable වගේ custom serialization methods වලට යන එක හොඳයි.

Conclusion

හරි, එහෙනම් කට්ටිය! අද අපි Java වල Serialization සහ Deserialization කියන්නේ මොකක්ද, ඒක කොහොමද වැඩ කරන්නේ, ඒක අපිට මොනවටද ඕන වෙන්නේ වගේ දේවල් ගැන විස්තරාත්මකව කතා කරා. Serializable interface එක, ObjectOutputStream, ObjectInputStream, සහ transient keyword එක ගැන හොඳටම පැහැදිලි වෙන්න ඇති කියලා හිතනවා. S/W Engineers විදියට අපිට, data persistence, network communication, RPC (Remote Procedure Call) වගේ ගොඩක් දේවල් වලට මේ concept එක අනිවාර්යයෙන්ම ඕන වෙනවා.

මතක තියාගන්න, coding කියන්නේ කරලා බලලා ඉගෙන ගන්න දෙයක්. ඒ නිසා, අදම ගිහින් පොඩි project එකක් හදලා මේවා apply කරලා බලන්න. ඔයාගේම objects serialize කරලා, deserialize කරලා, transient එක දාලා අයින් කරලා, නැති කරලා බලන්න. එතකොට තමා වැඩේ හරියටම අල්ලගන්න පුළුවන් වෙන්නේ. මොකද, අහලා ඉගෙන ගන්නවට වඩා, කරලා ඉගෙන ගන්න එක ගොඩක් හොඳයිනේ!

මේ article එක ගැන ඔයාගේ අදහස්, ප්‍රශ්න, මොනවා හරි තියෙනවා නම්, පහළින් comment එකක් දාගෙන යන්න. තව මොනවා ගැනද දැනගන්න කැමති කියලත් කියන්න. එහෙනම් අලුත් article එකකින් හමුවෙමු! Stay tuned, stay coding! ජය වේවා!