Implement the Serializable interface Make sure that instance-level, locally defined state is serialized properly

public DocumentDescriptionInputStream actualDocument, int documentType, boolean printTwoSided, int printQuality throws IOException { _documentType = documentType; _printTwoSided = printTwoSided; _printQuality = printQuality; BufferedInputStream buffer = new BufferedInputStreamactualDocument; DataInputStream dataInputStream = new DataInputStreambuffer; ByteArrayOutputStream temporaryBuffer = new ByteArrayOutputStream ; _length = copydataInputStream, ne w DataOutputStreamtemporaryBuffer; _actualDocument = new DataInputStreamnew ByteArrayInputStreamtemporaryBuffer.toByteArray ; } public int getDocumentType { return _documentType; } public boolean isPrintTwoSided { return _printTwoSided; } public int getPrintQuality { return _printQuality; } private int copyInputStream source, OutputStream destination throws IOException { int nextByte; int numberOfBytesCopied = 0; while-1= nextByte = source.read { destination.writenextByte; numberOfBytesCopied++; } destination.flush ; return numberOfBytesCopied; } } We will make this into a serializable class by following the steps outlined in the previous section.

10.3.5.1 Implement the Serializable interface

This is easy. All we need to do is change the class declaration: public class DocumentDescription implements Serialiazble, PrinterConstants

10.3.5.2 Make sure that instance-level, locally defined state is serialized properly

We have five fields to take care of: private InputStream _actualDocument; private int _length; private int _documentType; private boolean _printTwoSided; private int _printQuality; Of these, four are primitive types that serialization can handle without any problem. However, _actualDocument is a problem. InputStream is not a serializable class. And the contents of _actualDocument are very important; _actualDocument contains the document we want to print. There is no point in serializing an instance of DocumentDescription unless we somehow serialize _actualDocument as well. If we have fields that serialization cannot handle, and they must be serialized, then our only option is to implement readObject and writeObject . For Document - Description , we declare _actualDocument to be transient and then implement readObject and writeObject as follows: private transient InputStream _actualDocument; private void writeObjectjava.io.ObjectOutputStream out throws IOException { out.defaultWriteObject ; copy_actualDocument, out; } private void readObjectjava.io.ObjectInputStream in throws IOException, ClassNotFoundException { in.defaultReadObject ; ByteArrayOutputStream temporaryBuffer = new ByteArrayOutputStream ; copyin, temporaryBuffer, _length; _actualDocument = new DataInputStreamnew ByteArrayInputStreamtemporaryBuffer.toByteArray ; } private void copyInputStream source, OutputStream destination, int length throws IOException { int counter; int nextByte; for counter = 0; counter length; counter++ { nextByte = source.read ; destination.writenextByte; } destination.flush ; } Note that we declare _actualDocument to be transient and call defaultWriteObject in the first line of our writeObject method. Doing these two things allows the standard serialization mechanism to serialize the other four instance variables without any extra effort on our part. We then simply copy _actualDocument to the stream. Our implementation of readObject simply calls defaultReadObject and then reads _actualDocument from the stream. In order to read _actualDocument from the stream, we used the length of the document, which had previously been written to the stream. In essence, we needed to encode some metadata into the stream, in order to correctly pull our data out of the stream. This code is a little ugly. Were using serialization, but were still forced to think about how to encode some of our state when were sending it out of the stream. In fact, the code for writeObject and readObject is remarkably similar to the marshalling code we implemented directly for the socket-based version of the printer server. This is, unfortunately, often the case. Serializations default implementation handles simple objects very well. But, every now and then, you will want to send a nonserializable object over the wire, or improve the serialization algorithm for efficiency. Doing so amounts to writing the same code you write if you implement all the socket handling yourself, as in our socket-based version of the printer server. There is also an order dependency here. The first value written must be the first value read. Since we start writing by calling defaultWriteObject , we have to start reading by calling default - ReadObject . On the bright side, this means well have an accurate value for _length before we try to read _actualDocument from the stream.

10.3.5.3 Make sure that superclass state is handled correctly