Sobes.tech
Middle+

How to change the default behavior of serialization and deserialization in Java?

sobes.tech AI

Answer from AI

To modify the default serialization and deserialization behavior, writeObject and readObject methods are used, as well as the Externalizable mechanism.

Using writeObject and readObject

A class implementing Serializable can declare these methods. JVM will call them during serialization and deserialization respectively.

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

public class MyCustomSerializable implements Serializable {

    private String data;
    private transient int sensitiveData; // this field will not be serialized by default

    public MyCustomSerializable(String data, int sensitiveData) {
        this.data = data;
        this.sensitiveData = sensitiveData;
    }

    // Called during serialization
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject(); // serialize non-transient fields
        out.writeInt(sensitiveData * 2); // serialize modified sensitiveData
    }

    // Called during deserialization
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject(); // deserialize non-transient fields
        this.sensitiveData = in.readInt() / 2; // restore sensitiveData
    }

    // getters and setters
}

Using Externalizable

The Externalizable interface provides full control over serialization/deserialization. The class must implement writeExternal and readExternal.

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

public class MyExternalizable implements Externalizable {

    private String publicData;
    private int privateData; // all fields are serialized/deserialized manually

    // No-arg constructor is required
    public MyExternalizable() {
        // empty constructor
    }

    public MyExternalizable(String publicData, int privateData) {
        this.publicData = publicData;
        this.privateData = privateData;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(publicData); // manual serialization
        out.writeInt(privateData); // manual serialization
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.publicData = in.readUTF(); // manual deserialization
        this.privateData = in.readInt(); // manual deserialization
    }

    // getters and setters
}

Comparison

Feature Serializable + writeObject/readObject Externalizable
Control Partial (complement to default) Full
Implementation complexity Simpler for basic cases More code for all fields
Performance Usually lower Can be higher with optimization
Version compatibility Better JVM support Manual version management
transient fields Ignored by default Must be handled manually
Constructor No-arg constructor recommended No-arg constructor required