Serialization Object Persistence in Java Object Serialization Persistence
Serialization Object Persistence in Java
Object Serialization : Persistence • How do you save and restore program state? • When you “roll your own” code, saving and restoring is easy to understand (even if the code is sometimes fragile) • Components complicate things-- you need a standard way of telling a component to save and restore itself
The Basic Idea • Save everything to a stream • java. io defines two serialization streams – Object. Output. Stream: for saving – Object. Input. Stream: for restoring • Create the stream and tell it “save this object” using a standard API
Serializable objects • A serializable object is one that implements the java. io. Serializable interface (definition) – java. io. Serializable doesn’t define any method (it’s a marker interface) • In addition, a serializable object must have a zero-argument constructor – Otherwise, deserialization won’t work (need to create an object from scratch then loads its members)
The Standard Mechanism • Object. Output. Stream is responsible for tracking whether an object has already been serialized – If it has, simply write out a handle • Otherwise, write out the object • Either the object is default serializable or it requires special handling
Default Serialization • In most cases, serializing an instance consists of saving variable values • If an object is default serializable, the serialization mechanism will use reflection to – get all the fields – get their values – save them to the stream • recursing when the value is an object
Things to watch out for • An object is default-serializable iff all the nonstatic, non-transient data members are serializable – An object can easily inherit “serializability” (for example, by subclassing JComponent) – If it has a non-serializable data member, you need to be careful • Anonymous inner classes can’t be serialized
Object Serialization • reading and writing objects is a process called object serialization • Useful for: – Remote Method Invocation (RMI)--communication between objects via sockets – Lightweight persistence--the archival of an object for use in a later invocation of the same program. • An object is serializable only if its class implements the Serializable interface.
Writing objects • the write. Object method serializes the specified object, traverses its references to other objects recursively, and writes them all. File. Output. Stream out = new File. Output. Stream("the. Time"); Object. Output. Stream s = new Object. Output. Stream(out); s. write. Object("Today"); s. write. Object(new Date()); s. flush();
Reading Objects • objects must be read from the stream in the same order in which they were written • read. Object deserializes the object and traverses its references to other objects recursively to deserialize all objects that are reachable from it. File. Input. Stream in = new File. Input. Stream("the. Time"); Object. Input. Stream s = new Object. Input. Stream(in); String today = (String)s. read. Object(); Date date = (Date)s. read. Object();
Making a class serializable • Implements Serializable public class My. Serializable. Class implements Serializable {. . . } • Serializable is empty! – No additional method needed – serialization of instances of this class are handled by the default. Write. Object method of Object. Output. Stream that writes: • Class of the object • Class signature • Values of all non-transient and non-static members, including members that refer to other objects
Customizing Serialization • default serialization can be slow • want more explicit control over the serialization private void write. Object(Object. Output. Stream s) throws IOException { s. default. Write. Object(); // customized serialization code } private void read. Object(Object. Input. Stream s) throws IOException { s. default. Read. Object(); // customized deserialization code. . . // followed by code to update the object, if necessary }
Serialization uses Reflection • Is object serializable ? • Calling zero-argument constructor (must be public) • Finding read. Object / write. Object methods (and calling them) • Getting field values if object is default serializable (and checking whether the fields are transient) • Calling superclasses to get superclass state into serialization stream
Serialization Can Be Slow • Reflection is slow • Frequently objects contain redundant state – For example: an object that contains “cached summary information that can be deduced from other data • Example: Military. Convoy has an int number. Of. Vehicles and an Array. List named vehicle. List • Secondary goal: minimize length of resulting stream (save bandwidth and space) • Class is identified with – private static final serial. Version. UID • Full control on serialization is achieved with interface Externalizable
Transient as an Optimization • Use transient to help eliminate redundant data • Pro: Makes stream smaller / speeds computation – If the transient field is primitive, you gain a little. – If transient field is an object, you avoid navigating the instance graph (potentially big) • Cons: You had theat redundancy in there for a reason
Transients and Statics • transient is a keyword in the java language. – It tells the default serialization mechanism to ignore the value (the check to see which members are transient is again, a reflective one) • Static variables aren’t serialized by the default mechanism either
Examples of transients • In Swing, the pointer to the UI object is a transient (there’s no point in serializing the UI drawing code) • In the Collections library, the way that iterators keep track of a mutable Collection (to determine whether the underlying collection has changed) is transient • Pointers to stateless singletons are usually transient
Externalization in java • Custom serialization • Serialization by using Externalizable interface and implementing its two main methods – void read. External(Object. Input in) – void write. External(Object. Output out) 18
An important note about sockets • • (Only if you are going to program in Java) According to the API documentation for Object. Input. Stream's constructor: The stream header containing the magic number and version number are read from the stream and verified. This method will block until the corresponding Object. Output. Stream has written and flushed the header. This is a very important point to be aware of when trying to send objects in both directions over a socket because opening the streams in the wrong order will cause deadlock. Consider for example what would happen if both client and server tried to construct an Object. Input. Stream from a socket's input stream, prior to either constructing the corresponding Object. Output. Stream. The Object. Input. Stream constructor on the client would block, waiting for the magic number and version number to arrive over the connection, while at the same time the Object. Input. Stream constructor on the server side would also block for the same reason. Hence, deadlock. Because of this, you should always make it a practice in your code to open the Object. Output. Stream and flush it first, before you open the Object. Input. Stream. The Object. Output. Stream constructor will not block, and invoking flush() will force the magic number and version number to travel over the wire. If you follow this practice in both your client and server, you shouldn't have a problem with deadlock.
- Slides: 19