The format for the default structure of a serialized object is similar, but not identical, to the structure of a class file. The Sun documentation describes in detail the format of the Object Serialization Stream. The example code writes files that may be opened with a text editor, so you can inspect the serialized objects.
ObjectReaderWriter is the primary application class. At runtime it displays a "Save As..." FileDialog, allowing you to specify an output file to receive the stream containing the serialized objects. (All the sample objects are written to the same file.) It then prompts for an input file from which to read a stream.
This arrangement of the sample code allows you to write out the serialized data to one file, make changes to the class format for one or more of the data classes, recompile and rerun, and attempt to read one of the older versions back in.
The class MySerialObject contains a reference to an instance of the class MyInternalObject, to demonstrate the saving of nested object references in the stream. MySerialObject also contains a field (of type int) that is marked transient, and upon restoration you will find that the default value 0 gets assigned to that variable.
The class MyVersionObject demonstrates the use of versioning with a programmer-specified SUID. You only need to change the SUID when you make changes to the class structure that render it incompatible with older versions of that same class, and whose serialized instances have previously been written to disk.
You can compile the .java (source) files using the javac (Java compiler) tool included in the MRJ SDK Tools folder, or using the Java compiler in CodeWarrior or Visual Cafe. You can then optionally create a .jar (Java archive) file containing the resulting .class (output) files.
The archive for this article includes the .java and .class files, and a .jar file containing the .class files. To run the program, drag either the file ObjectReaderWriter.class or ObjectReaderWriter.jar onto the JBindery application icon, which is located in the MRJ SDK JBindery folder. Once JBindery launches, it will display ObjectReaderWriter in the "class name" field. (This field specifies the name of the class to run at application startup; that class must contain a main() method.) Click OK to run the program.
ObjectReaderWriter.java The class that will read and write serialized and externalized objects.
Listing 2: MyInternalObject.java
MyInternalObject.java The nested data class.
Listing 3: MyVersionObject.java
transient keyword Example
Externalized class example
Example Code
The following code illustrates the writing and reading of Serializable.ObjectReaderWriter is the primary application class. At runtime it displays a "Save As..." FileDialog, allowing you to specify an output file to receive the stream containing the serialized objects. (All the sample objects are written to the same file.) It then prompts for an input file from which to read a stream.
This arrangement of the sample code allows you to write out the serialized data to one file, make changes to the class format for one or more of the data classes, recompile and rerun, and attempt to read one of the older versions back in.
The class MySerialObject contains a reference to an instance of the class MyInternalObject, to demonstrate the saving of nested object references in the stream. MySerialObject also contains a field (of type int) that is marked transient, and upon restoration you will find that the default value 0 gets assigned to that variable.
The class MyVersionObject demonstrates the use of versioning with a programmer-specified SUID. You only need to change the SUID when you make changes to the class structure that render it incompatible with older versions of that same class, and whose serialized instances have previously been written to disk.
You can compile the .java (source) files using the javac (Java compiler) tool included in the MRJ SDK Tools folder, or using the Java compiler in CodeWarrior or Visual Cafe. You can then optionally create a .jar (Java archive) file containing the resulting .class (output) files.
The archive for this article includes the .java and .class files, and a .jar file containing the .class files. To run the program, drag either the file ObjectReaderWriter.class or ObjectReaderWriter.jar onto the JBindery application icon, which is located in the MRJ SDK JBindery folder. Once JBindery launches, it will display ObjectReaderWriter in the "class name" field. (This field specifies the name of the class to run at application startup; that class must contain a main() method.) Click OK to run the program.
ObjectReaderWriter.java The class that will read and write serialized and externalized objects.
import java.awt.*;
import java.io.*;
public class ObjectReaderWriter {
String filePath;
public static void main( String args[] ) {
ObjectReaderWriter orw = new ObjectReaderWriter();
}
ObjectReaderWriter() {
try {
// Create instances of each data class to be serialized.
MySerialObject serialObject = new MySerialObject();
MyExternObject externObject = new MyExternObject();
MyVersionObject versionObject = new MyVersionObject();
// Allow the user to specify an output file.
FileDialog fd = new FileDialog( new Frame(),
"Save As...", FileDialog.SAVE );
fd.show();
filePath = new String( fd.getDirectory() + fd.getFile() );
// Create a stream for writing.
FileOutputStream fos = new FileOutputStream( filePath );
// Next, create an object that can write to that file.
ObjectOutputStream outStream =
new ObjectOutputStream( fos );
// Save each object.
outStream.writeObject( serialObject );
externObject.writeExternal( outStream );
outStream.writeObject( versionObject );
// Finally, we call the flush() method for our object, which
forces the data to
// get written to the stream:
outStream.flush();
// Allow the user to specify an input file.
fd = new FileDialog( new Frame(), "Open...",
FileDialog.LOAD );
fd.show();
filePath = new String( fd.getDirectory() + fd.getFile() );
// Create a stream for reading.
FileInputStream fis = new FileInputStream( filePath );
// Next, create an object that can read from that file.
ObjectInputStream inStream = new ObjectInputStream( fis );
// Retrieve the Serializable object.
serialObject = ( MySerialObject )inStream.readObject();
// Display what we retrieved:
System.out.println( serialObject.getS() );
System.out.println( "i = " + serialObject.getI() );
serialObject.displayInternalObjectAttrs();
// Retrieve the Externalizable object.
externObject.readExternal( inStream );
// Display what we retrieved:
System.out.println( externObject.getS() );
System.out.println( "i = " + externObject.getI() );
// Retrieve the versioned object.
versionObject = ( MyVersionObject )
inStream.readObject();
// Display what we retrieved:
System.out.println( versionObject.getS() );
System.out.println( "i = " + versionObject.getI() );
// Display the SUID of the versioned class in the VM,
// not necessarily the serialized object.
ObjectStreamClass myObject = ObjectStreamClass.lookup(
Class.forName( "MyVersionObject" ) );
long theSUID = myObject.getSerialVersionUID();
System.out.println
( "The SUID of class MyVersionObject = " + theSUID );
}
catch ( InvalidClassException e ) {
System.out.println( "InvalidClassException..." );
}
catch ( ClassNotFoundException e ) {
System.out.println( "ClassNotFoundException..." );
}
catch ( OptionalDataException e ) {
System.out.println( "OptionalDataException..." );
}
catch ( FileNotFoundException e ) {
System.out.println( "FileNotFoundException..." );
}
catch ( IOException e ) {
System.out.println( "IOException..." );
}
}
}
Listing 2: MyInternalObject.java
MyInternalObject.java The nested data class.
import java.io.*;
public class MyInternalObject implements Serializable {
private int i;
private String s;
MyInternalObject() {
i = 128;
s = new String( "Instance of MyInternalObject..." );
}
public int getI() {
return i;
}
public String getS() {
return s;
}
}
Listing 3: MyVersionObject.java
MyVersionObject.java The versioned data class.
import java.io.*;
public class MyVersionObject implements Serializable
{
static final long serialVersionUID = 1L;
private int i; private String s;
// Uncomment the next two lines to verify that default values will
// be substituted if
// the value is not present in the stream at deserialization time.
// private int i2 = -1;
// private String s2 = "This is the new String field";
MyVersionObject() {
i = 512;
s = new String( "Instance of MyVersionObject..." );
}
public int getI() {
return i;
}
public String getS() {
return s;
}
}
transient keyword Example
Externalized class example
No comments:
Post a Comment