Serialization is a fundamental concept in Java programming that allows objects to be converted into a format suitable for storage or transmission. It plays a crucial role in tasks such as persisting object state, sending objects over a network, or even for caching purposes. In this article, we will delve into the world of Java serialization, exploring its mechanics, use cases, best practices and potential pitfalls.

Featured Partners

What is serialization?

Serialization is the process of converting an object into a format that can be easily stored, transmitted or reconstructed later. Serialization is particularly useful when you need to save the state of an object to disk, send it over a network or pass it between different parts of a program.

Java employs its own binary serialization stream protocol. Serialization is achieved through a combination of the ObjectOutputStream and ObjectInputStream classes, and the implementation of marker interfaces Serializable and Externalizable.

See Also: Java directory navigation

How serialization works in Java

ObjectOutput/InputStream

The core of Java serialization lies in the ObjectOutputStream and ObjectInputStream classes. These streams provide methods to write and read objects. Here’s a simple example of serializing an object:

// Serialization
try (ObjectOutputStream out =
  new ObjectOutputStream(new FileOutputStream("data.dat"))) {
    MyClass obj = new MyClass("John Doe", 25);
    out.writeObject(obj);
} catch (IOException e) {
    e.printStackTrace();
}

// Deserialization
try (ObjectInputStream in =
  new ObjectInputStream(new FileInputStream("data.dat"))) {
    MyClass obj = (MyClass) in.readObject();
    System.out.println(obj.getName()); // Outputs: John Doe
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

Serializable interface

To enable serialization, a class must implement the Serializable interface. This is known as a marker interface, meaning it doesn’t have any methods, but it serves as a flag to the Java Virtual Machine that the class can be serialized. If a class doesn’t implement Serializable and you try to serialize an instance of it, a java.io.NotSerializableException will be thrown.

import java.io.Serializable;

public class MyClass implements Serializable {
  private String name;
  private int age;
  // Constructor, getters, setters, etc.
}

Externalizable interface

In addition to Serializable, Java provides the Externalizable interface. Unlike Serializable, which handles serialization automatically, Externalizable allows you to have complete control over the serialization process by implementing two methods: writeExternal and readExternal.

import java.io.Externalizable;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.IOException;

public class MyExternalizableClass implements Externalizable {
  private String name;
  private int age;

  // Constructor, getters, setters, etc.

  @Override
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeObject(name);
    out.writeInt(age);
}

  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    name = (String) in.readObject();
    age = in.readInt();
  }
}

Serialization and object graphs

When you serialize an object, it’s important to note that the entire object graph is serialized. This means that if your object contains references to other objects, those will be serialized as well. This can lead to unexpected behavior if the referenced objects aren’t themselves serializable.

public class Person implements Serializable {
  private String name;
  private Address address;

  // Constructor, getters, setters, etc.
}

public class Address {
  private String street;
  private String city;

  // Constructor, getters, setters, etc.
}

In this example, if Address doesn’t implement Serializable, a java.io.NotSerializableException will be thrown when trying to serialize a Person object.

See Also: Top Java IDEs and Code Editors

Customizing serialization

Controlling serialization with writeObject() and readObject()

Sometimes, you may need more control over the serialization process. This can be achieved by implementing writeObject() and readObject() methods in your class. These methods are called during serialization and deserialization, allowing you to define custom behavior.

private void writeObject(ObjectOutputStream out)
  throws IOException {
    // Custom serialization code here
}

private void readObject(ObjectInputStream in)
  throws IOException, ClassNotFoundException {
    // Custom deserialization code here
}

Using writeReplace() and readResolve()

The writeReplace() and readResolve() methods provide another level of customization. They allow you to specify alternative objects to be used during serialization and deserialization. This is often used to ensure that a singleton class remains a singleton after deserialization.

private Object writeReplace() throws ObjectStreamException {
  return someReplacementObject;
}

private Object readResolve() throws ObjectStreamException {
  return someActualObject;
}

Versioning and compatibility

As your application evolves, so do your classes. It’s important to consider versioning when dealing with serialized objects. This is to ensure that older versions of your application can still deserialize objects saved by newer versions and vice versa.

This can be achieved by providing a serialVersionUID field in your class. This field is a unique identifier for the class and should be updated whenever the class is modified in a way that affects serialization compatibility.

private static final long serialVersionUID = 1L;

Security considerations

Serialization and deserialization can introduce security risks, especially when dealing with untrusted data. It’s recommended to validate input and consider using techniques such as object filtering or using a whitelist of allowed classes during deserialization.

Performance implications

While serialization is a convenient way to persist object state, it can have performance overhead, especially for large object graphs. Consider using alternative serialization libraries such as Kryo or Protocol Buffers if performance is a critical concern.

Common pitfalls and best practices

  • Forgetting to implement serializable: This is a common mistake, so always ensure that any class you intend to serialize implements the Serializable interface.
  • Not handling object graphs: Be aware that when you serialize an object, its entire object graph is serialized, so make sure all objects in the graph are serializable.
  • Versioning: Keep track of serialVersionUID and update it appropriately when making changes to serialized classes.

Alternative serialization libraries

While Java’s built-in serialization mechanism is powerful, it may not always be the most efficient option. Consider exploring libraries such as Kryo, Protocol Buffers or Jackson for more specialized use cases.

Final thoughts on serialization in Java

Java serialization is a versatile tool that enables the persistence and transmission of object state. By understanding the mechanics, customization options, versioning and security considerations, you can effectively leverage serialization in your applications. Remember to always keep performance in mind and consider alternative serialization libraries for specific use cases. With these skills in hand, you’ll be well-equipped to handle a wide range of tasks involving object serialization in Java.

Featured Partners

1 Zoho Assist

Visit website

With Zoho Assist File transfer, you can send and receive files and folders during your remote sessions. Effortlessly transfer and manage files as large as 5 GB in size with no maximum limit for a single transfer. Files of all formats can be shared without dependence on intermediate storage, like USBs or cloud-based storage devices, keeping your workflow uninterrupted and your data protected.

Learn more about Zoho Assist

Subscribe to the Developer Insider Newsletter

From the hottest programming languages to commentary on the Linux OS, get the developer and open source news and tips you need to know. Delivered Tuesdays and Thursdays

Subscribe to the Developer Insider Newsletter

From the hottest programming languages to commentary on the Linux OS, get the developer and open source news and tips you need to know. Delivered Tuesdays and Thursdays