Jun 29, 2015

Serialization: Part-2

The stream manipulation methods
ObjectOutputStream also implements four methods that deal with the basic mechanics of manipulating the stream:
 public void reset( );  
 public void close( );  
 public void flush( );  
 public void useProtocolVersion(int version);  
With the exception of useProtocolVersion( ), these methods should be familiar. In fact, reset( ), close ( ), and flush( ) are standard stream methods. useProtocolVersion(), on the other hand, changes the version of the serialization mechanism that is used. This is necessary because the serialization format and algorithm may need to change in a way that's not backwards-compatible. If another application needs to read in your serialized data, and the applications will be versioning independently (or running in different versions of the JVM), you may want to standardize on a protocol version.

ObjectInputStream
ObjectInputStream , defined in the java.io package, implements the "reading-in" part of the serialization algorithm. It is the companion to ObjectOutputStream™ objects serialized using ObjectOutputStream can be deserialized using ObjectInputStream. Like ObjectOutputStream, the methods implemented by ObjectInputStream can be grouped into three categories: methods that read information from the stream, methods that are used to control the stream's behavior, and methods that are used to customize the serialization algorithm.
The "read" methods
The first, and most intuitive, category consists of the "read" methods:
 public int read( );  
 public int read(byte[] b, int off, int len);  
 public boolean readBoolean( );  
 public byte readByte( );  
 public char readChar( );  
 public double readDouble( );  
 public float readFloat( );  
 public intreadInt( );  
 public long readLong( );  
 public Object readObject( );  
 public short readShort( );  
 public byte readUnsignedByte( );  
 public short readUnsignedShort( );  
 public String readUTF( );  
 void defaultReadObject( );  
Just as with ObjectOutputStream's write( ) methods, these methods should be familiar. readFloat( ), for example, reads four bytes from the stream and converts them into a single floating-point number, which is returned by the method call. And, again as with ObjectOutputStream, there are two new methods here: readObject( ) and defaultReadObject( ). Just as writeObject( ) serializes an object, readObject( ) deserializes it. Deserializing an object involves doing two things: creating an ObjectInputStream and then calling readObject( ). The following code snippet shows the entire process, creating a copy of an object (and all the objects to which it refers) from a file:
 FileInputStream underlyingStream = new FileInputStream("C:\\temp\\test");  
 ObjectInputStream deserializer = new ObjectInputStream(underlyingStream);  
 Object deserializedObject = deserializer.readObject( );  
This code is exactly inverse to the code we used for serializing the object in the first place. If we wanted to make a deep copy of a serializable object, we could first serialize the object and then deserialize it, as in the following code example:
 ByteArrayOutputStream memoryOutputStream = new ByteArrayOutputStream();  
 ObjectOutputStream serializer = new ObjectOutputStream(memoryOutputStream);  
 serializer.writeObject(serializableObject);  
 serializer.flush( );  
 ByteArrayInputStream memoryInputStream = new ByteArrayInputStream(memoryOutputStream.toByteArray( ));  
 ObjectInputStream deserializer = new ObjectInputStream(memoryInputStream);  
 Object deepCopyOfOriginalObject = deserializer.readObject( );  
This code simply places an output stream into memory, serializes the object to the memory stream, creates an input stream based on the same piece of memory, and runs the deserializer on the input stream. The end result is a deep copy of the object with which we started.

The stream manipulation methods
There are five basic stream manipulation methods defined for ObjectInputStream:
 public boolean available( );  
 public void close( );  
 public void readFully(byte[] data);  
 public void readFully(byte[] data, int offset, int size);  
 public int skipBytes(int len);  
Of these, available( ) and skip( ) are methods first defined on InputStream. available( ) returns a boolean flag indicating whether data is immediately available, and close( ) closes the stream. The three new methods are also straightforward. skipBytes( ) skips the indicated number of bytes in the stream, blocking until all the information has been read. And the two readFully( ) methods perform a batch read into a byte array, also blocking until all the data has been read in.

Methods that customize the serialization mechanism
The last group of methods consists mostly of protected methods that provide hooks, which allow the serialization mechanism itself, rather than the data associated to a particular class, to be customized. These methods are:
 protected boolean enableResolveObject(boolean enable);  
 protected Class resolveClass(ObjectStreamClass v);  
 protected Object resolveObject(Object obj);  
 protected class resolveProxyClass(String[] interfaces);  
 protected ObjectStreamClass readClassDescriptor( );  
 protected Object readObjectOverride( );  
 protected void readStreamHeader( );  
 public void registerValidation(ObjectInputValidation obj, int priority);  
 public GetFields readFields( );  
These methods are more important to people who tailor the serialization algorithm to a particular use or develop their own implementation of serialization. Like before, they also require a deeper understanding of the serialization algorithm, so I'll hold off on discussing them right now.

Continue to Part 3 for understanding How to make class Serializable.

0 comments:

Post a Comment