Skip to main content
Advertisement

Serialization

Instances (objects) created during program execution operate exclusively inside the JVM's Heap memory space, and universally vanish when the entire program is eventually terminated. If the state of such an object (the specific values preserved in its fields) requires permanent storage in a file, or if there is a necessity to transmit it continuously via a network directly to another server's JVM, developers employ a mechanism termed Serialization.

  • Serialization: The complex process of systematically transforming an object actively residing in memory into a contiguous byte sequence (Byte Stream).
  • Deserialization: The exact reverse procedure—successfully taking a received or stored byte sequence and identically reconstructing it back to its original object architecture format.

1. Applying the Serializable Interface

Objects are strictly authorized to be serialized only if their class explicitly incorporates (implements) the java.io.Serializable interface. Noticeably, this interface operates identically to a marker interface—symbolizing "Serialization is permitted for this class" while requiring entirely zero methods to be forcefully overridden.

import java.io.Serializable;

// A thoroughly serializable UserInfo class
class UserInfo implements Serializable {
// A highly recommended unique ID used exclusively for reliable Serialization version control
private static final long serialVersionUID = 1L;

String name;

// Variables declared with the 'transient' keyword are intentionally excluded structurally from serialization (often applied defensively for security purposes).
transient String password;

int age;

public UserInfo(String name, String password, int age) {
this.name = name;
this.password = password;
this.age = age;
}
}

2. Utilizing ObjectOutputStream / ObjectInputStream

These dedicated filter streams dynamically record or conversely retrieve native objects.

import java.io.*;

public class SerialEx {
public static void main(String[] args) {
UserInfo u1 = new UserInfo("Alice", "1234", 30);
String fileName = "userinfo.ser";

// 1. Serialize an object directly and structurally save it thoroughly to a file
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) {
out.writeObject(u1);
System.out.println("The localized object was reliably serialized and actively stored securely.");
} catch (IOException e) {
e.printStackTrace();
}

// 2. Extensively read bytes straight from the identical file and confidently deserialize it back perfectly
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) {
// Because it was recorded aggressively with writeObject(), readObject() is utilized to read and down-cast it appropriately.
UserInfo readUser = (UserInfo) in.readObject();

System.out.println("Restored Name: " + readUser.name);
System.out.println("Restored Age: " + readUser.age);
System.out.println("Password (transient): " + readUser.password); // Critically prints completely null!

} catch (Exception e) {
e.printStackTrace();
}
}
}

In dynamically deployed modern distributed backend architectures or conventional web frameworks, utilizing this inherent Java Serialization pattern introduces subtle yet fatal security complexities and framework incompatibility implications. Thus, aggressively migrating towards securely transforming complex elements exclusively into generic JSON format representation remains the fundamentally optimized industrial standard (i.e. extensively employing modern generic parsing libraries specifically like Jackson or Gson).

Advertisement