The JavaTM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: Essential Java Classes
Lesson: Reading and Writing (but no 'rithmetic)

## Providing Object Serialization for Your Classes

> An object is serializable only if its class implements the `Serializable` interface. Thus, if you want to serialize the instances of one of your classes, the class must implement the `Serializable` interface. The good news is that `Serializable` is an empty interface. That is, it doesn't contain any method declarations; it's purpose is simply to identify classes whose objects are serializable.

### Implementing the Serializable Interface

> Here's the complete definition of the `Serializable` interface:

> >     package java.io;
> >     public interface Serializable {
> >         // there's nothing in here!
> >     };

> Making instances of your classes serializable is easy. You just add the `implements Serializable` clause to your class declaration like this:

> >     public class MySerializableClass implements Serializable {
> >         ...
> >     }

> You don't have to write any methods. The serialization of instances of this class are handled by the `defaultWriteObject` method of `ObjectOutputStream`. This method automatically writes out everything required to reconstruct an instance of the class, including the following:
> - Class of the object
> - Class signature
> - Values of all non-`transient` and non-`static` members, including members that refer to other objects
> For many classes, this default behavior is good enough. However, default serialization can be slow, and a class might want more explicit control over the serialization.

### Customizing Serialization

> You can customize serialization for your classes by providing two methods for it: `writeObject` and `readObject`. The `writeObject` method controls what information is saved. It is typically used to append additional information to the stream. The `readObject` method either reads the information written by the corresponding `writeObject` method or can be used to update the state of the object after it has been restored.

> The `writeObject` method must be declared exactly as shown in the following example. Also, it should call the stream's `defaultWriteObject` as the first thing it does to perform default serialization. Any special arrangements can be handled afterwards:

> >     private void writeObject(ObjectOutputStream s)
> >                              throws IOException {
> >         s.defaultWriteObject();
> >         // customized serialization code
> >     }

> The `readObject` method must read in everything written by `writeObject` in the same order in which it was written. Also, the `readObject` method can perform calculations or update the state of the object in some way. Here's the `readObject` method that corresponds to the `writeObject` method just shown:

> >     private void readObject(ObjectInputStream s)
> >                             throws IOException  {
> >         s.defaultReadObject();
> >         // customized deserialization code
> >         ...
> >         // followed by code to update the object, if necessary
> >     }

> The `readObject` method must be declared exactly as shown.

> The `writeObject` and `readObject` methods are responsible for serializing only the immediate class. Any serialization required by the superclasses is handled automatically. However, a class that needs to explicitly coordinate with its superclasses to serialize itself can do so by implementing the `Externalizable` interface.

### Implementing the Externalizable Interface

> For complete, explicit control of the serialization process, a class must implement the `Externalizable` interface. For `Externalizable` objects, only the identity of the object's class is automatically saved by the stream. The class is responsible for writing and reading its contents, and it must coordinate with its superclasses to do so.

> Here's the complete definition of the `Externalizable` interface that extends `Serializable`:

> >     package java.io;
> >     public interface Externalizable extends Serializable
> >     {
> >         public void writeExternal(ObjectOutput out)
> >                                   throws IOException;
> >         public void readExternal(ObjectInput in)
> >                                  throws IOException,
> >                                  java.lang.ClassNotFoundException;
> >     }

> The following holds for an `Externalizable` class:
> - It must implement the `java.io.Externalizable` interface.
> - It must implement a `writeExternal` method to save the state of the object. Also, it must explicitly coordinate with its supertype to save its state.
> - It must implement a `readExternal` method to read the data written by the `writeExternal` method from the stream and restore the state of the object. It must explicitly coordinate with the supertype to restore its state.
> - If externally defined format is being written, the `writeExternal` and `readExternal` methods are solely responsible for that format.
> The `writeExternal` and `readExternal` methods are public and carry the risk that a client may be able to write or read information in the object other than by using its methods and fields. These methods must be used only when the information held by the object is not sensitive or when exposing that information would not present a security risk.

### Protecting Sensitive Information

> When developing a class that provides controlled access to resources, you must take care to protect sensitive information and functions. During deserialization, the private state of the object is restored. For example, a file descriptor contains a handle that provides access to an operating system resource. Being able to forge a file descriptor would allow some forms of illegal access, since restoring state is done from a stream. Therefore the serializing runtime must take the conservative approach and not trust the stream to contain only valid representations of objects. To avoid compromising a class, you must provide either that the sensitive state of an object must not be restored from the stream or that it must be reverified by the class.

> Several techniques are available to protect sensitive data in classes. The easiest is to mark fields that contain sensitive data as private `transient`. `transient` and `static` fields are not serialized or deserialized. Marking the field will prevent the state from appearing in the stream and from being restored during deserialization. Since writing and reading (of private fields) cannot be superseded outside of the class, the class's `transient` fields are safe.

> Particularly sensitive classes should not be serialized. To accomplish this, the object should not implement either the `Serializable` or `Externalizable` interface.

> Some classes may find it beneficial to allow writing and reading but to specifically handle and revalidate the state as it is deserialized. The class should implement `writeObject` and `readObject` methods to save and restore only the appropriate state. If access should be denied, throwing a `NotSerializableException` will prevent further access.

| Start of Tutorial > Start of Trail > Start of Lesson | Search