/*
*
* @(#)EvolvedClass.java 1.7 98/10/01
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*
*/
import java.io.*;
import java.awt.*;
/**
*
* This example shows how to use the Serializable Fields API with
* Serialization, demonstrating that the class can define fields
* other than those already in the class to be serializable. This
* differs from just rewriting the writeObject method to customize
* the data format (see the Custom Data Format example) because,
* in this example, versioning support still holds.
*
* Using the Serializable Fields API, this example specifically
* changes the internal representation of a rectangle from
* x1,y1,x2,y2 implementation (see Original Class) to Point(x1,y1),
* Point(x2,y2) (see Evolved Class) while the external representation
* still remains x1, y1, x2, y2. This ensures bidirectional compatibility
* between the original and evolved representations.
*
* The original rectangle class (in OriginalClass.java) consists of four
* integers (x1, y1, x2, y2). Instead of four integers, the evolved rectangle
* class (in this file) has two Points as fields. In order for this
* evolved class to fulfill its contract with the original class, the
* evolved class saves its fields as four integers (x1, y1, x2, y2)
* instead of two points. By doing this the evolved class ensures
* bidirectional compatibility with the original class.
*
* To see how to run this: see OriginalClass.java
*
* Compiled and Tested with JDK1.2
*/
public class EvolvedClass {
/**
* There are two options: either a user can serialize an object or
* deserialize it. (using the -s or -d flag). These options allow
* for the demonstration of bidirection readability and writeability
* between the original and the evolved class. In other words,
* one can serialize an object here and deserialize it with the evolved
* class or vice versa.
*/
public static void main(String args[]) {
ARectangle orgClass = new ARectangle(100, 100, 102, 102);
ARectangle newClass = null;
boolean serialize = false;
boolean deserialize = false;
/*
* see if we are serializing or deserializing.
* The ability to deserialize or serialize allows
* us to see the bidirectional readability and writeability
*/
if (args.length == 1) {
if (args[0].equals("-d")) {
deserialize = true;
} else if (args[0].equals("-s")) {
serialize = true;
} else {
usage();
System.exit(0);
}
} else {
usage();
System.exit(0);
}
/*
* Serialize the original class if that's the option chosen
*/
if (serialize) {
try {
FileOutputStream fo = new FileOutputStream("evolve.tmp");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(orgClass);
so.flush();
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
}
/*
* Deserialize, if that's the option chosen and print the name
* of the object, which will allow us to see who serialized the
* object, the original class or the evolved class file
*/
if (deserialize) {
try {
FileInputStream fi = new FileInputStream("evolve.tmp");
ObjectInputStream si = new ObjectInputStream(fi);
newClass = (ARectangle) si.readObject();
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
System.out.println("Now printing deserialized object: ");
System.out.println();
System.out.println(newClass);
}
}
/**
* Prints out the usage
*/
static void usage() {
System.out.println("Usage:");
System.out.println(" -s (in order to serialize)");
System.out.println(" -d (in order to deserialize)");
}
}
/**
* The evolved Rectangle Class. Interally consists of two fields of type
* Point but externally is still 4 integers (so that it is compatible
* with the original rectangle class)
*
* In order to make this possible, we need to use the Serializable
* Field API so that we can define serializable fields that are
* not part of the implementation class.
*/
class ARectangle implements java.io.Serializable {
// new rectangle representation
/**
* First of two points forming diagonal of rectangle.
*
* Note that this field is not a default serializable field
* due to the use of serialPersistentFields member within this class.
*/
Point point1;
/**
* Second of two points forming diagonal of rectangle.
*
* Note that this field is not a default serializable field
* due to the use of serialPersistentFields member within this class.
*/
Point point2;
/*
* mandatory SUID field for an evolved Serializable class.
* serialVersionUID is gotten by doing the serialver command
* on the original class:
* serialver ARectangle (the original rectangle)
*/
static final long serialVersionUID = 9030593813711490592L;
/**
* The special member, serialPeristentFields, explicitly declares
* Serializable fields for this class. This allows for fields other
* than the fields in the class to be persistent. Since we want to
* save the state of the two Points point1 and point2, we declare
* the 4 ints as the serial persistent fields
*
* @serialField x1 Integer
* X-coordinate of point 1 of diagonal points of rectangle.
* @serialField y1 Integer
* Y-coordinate of point 1 of diagonal points of rectangle.
* @serialField x2 Integer
* X-coordinate of point 2 of diagonal points of rectangle.
* @serialField y2 Integer
* Y-coordinate of point 2 of diagonal points of rectangle.
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("x1", Integer.TYPE),
new ObjectStreamField("y1", Integer.TYPE),
new ObjectStreamField("x2", Integer.TYPE),
new ObjectStreamField("y2", Integer.TYPE)
};
ARectangle(int x1, int y1, int x2, int y2) {
point1 = new Point(x1, y1);
point2 = new Point(x2, y2);
}
/**
* writeObject - Writes out the serializable fields
* (the 4 integers, x1, y1, x2, y2) using the
* Serializable Field API. (the methods putFields and
* writeFields of the ObjectOutputStream Class and the method put
* of the ObjectOutputStream.PutField inner class)
*
* @serialData Only the serializable fields of the class are written.
* No optional data written.
*/
private void writeObject(ObjectOutputStream s)
throws IOException {
// set the values of the Serializable fields
ObjectOutputStream.PutField fields = s.putFields();
fields.put("x1", point1.x);
fields.put("y1", point1.y);
fields.put("x2", point2.x);
fields.put("y2", point2.y);
// save them
s.writeFields();
}
/**
* readsObject - Reads in the serializable fields
* (the 4 integers, x1, y1, x2, y2) using the
* Serializable Field API. (the methods getFields and
* readFields of the ObjectInputStream Class and the method get
* of the ObjectOutputStream.GetField inner class)
*
* @serialData No optional data is read.
*/
private void readObject(ObjectInputStream s)
throws IOException {
// prepare to read the alternate persistent fields
ObjectInputStream.GetField fields = null;
try {
fields = s.readFields();
} catch (Exception ClassNotFoundException) {
throw new IOException();
}
// read the alternate persistent fields
int x1 = (int)fields.get("x1", 0);
int y1 = (int)fields.get("y1", 0);
int x2 = (int)fields.get("x2", 0);
int y2 = (int)fields.get("y2", 0);
// save them back as Points.
point1 = new Point(x1, y1);
point2 = new Point(x2, y2);
}
public String toString() {
return("point1.x: " + point1.x + "\npoint1.y: " + point1.y + "\npoint2.x: " + point2.x + "\npoint2.y: " + point2.y);
}
}
|