|
Geek-Tutorials.com
|
|
The ObjectOutputStream class is used for serializing objects into output stream. The serialized data can be store into local file and then later read by ObjectInputStream to deserialized it back to object instance. Serialization is often use as a way for saving application preferences and game state.
Classes must implement Serializable or Externalizable interfaces for ObjectOutputStream to serialize an instance of classes. ObjectOutputStream can serialize primitive types, classes and user defined classes. Following example show how to make object serializable by implementing Serializable interface.
package com.geek.tutorials.io.serializable;
import java.io.Serializable;
public class Class1 implements Serializable{ // Display Comment
int value;
public Class1(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
Following code show how you can serialize an serializable class to an ObjectOutputStream and store its state into local drive.
package com.geek.tutorials.io.serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
public class SerializableTest1 {
public static void main(String[] args) {
Class1 class1 = new Class1(5); // Display Comment
try{
// Display Comment FileOutputStream f = new FileOutputStream("serialize1.ser");
ObjectOutputStream out = new ObjectOutputStream(f);
out.writeObject(class1); //Display Comment out.flush();
out.close();
FileInputStream f2 = new FileInputStream("serialize1.ser");
ObjectInputStream in = new ObjectInputStream(f2);
Class1 c1 =(Class1)in.readObject(); //Display Commentin.close(); System.out.println(c1.getValue()); //Display Comment
}catch(Exception e){
System.out.println(e);
}
}
}
| protected ObjectOutputStream () | Constructs an instance of ObjectOutputStream. |
|
Syntax
Exception
Example | |
| public ObjectOutputStream (OutputStream out) | Constructs an instance of ObjectOutputStream that writes to OutputStream. |
|
Syntax
Parameters
Exception
Example | |
| protected void annotateClass (Class cl) | Allow Subclasses to store additional class data in the stream |
|
Syntax
Parameters
Exception
Description
Example For example, if we has a serialized object that its class might outdate in the future and must be replace by latest implementation of the class, we can solve this problem by overriding ObjectOutputStream.annotateClass() to write class's version number into the output stream (see example code in MyOutputStream below), and during the deserialization we can overrides ObjectInputStream.resolveClass() and ObjectInputStream.resolveObject() to check the version number of the serialized object and upgrade it if necessary (see example code in MyInputStream below). package com.geek.tutorials.io.ObjectOutputStream;
import java.io.*;
class MyOutputStream extends ObjectOutputStream{
float version;
public MyOutputStream(OutputStream out) throws IOException{
super(out);
}
protected void annotateClass(Class cl) throws IOException{ // Display Comment Subclass of ObjectOutputStream that overrides annotateClass() method,
it execute only once per all object of the same class until out.reset() is call.
This code here write 'version' information to the output stream prior to serialization of the actual object.
writeFloat(version);
}
public void setVersion(float version){ // Display Comment Set Object's version number, this method should be call before calling writeObject();
this.version = version;
}
}
class MyInputStream extends ObjectInputStream{
float version;
public MyInputStream(InputStream in)throws IOException, ClassNotFoundException{
super(in);
enableResolveObject(true); // Display Comment Enable overrided resolveObject(), our overrided resolveObject() will never execute without setting 'true' into this method.
}
protected Object resolveObject(Object obj){ // Display Comment If version is not latest(e.g. 2.0), then upgrade the deserializing 1.0 class and return it as 2.0 class, else if it is latest class implementation, then do nothing and simply return it to readObject().
if(version != 2.0f)
return new SimpleClass2(((SimpleClass1)obj).getValue());
else
return obj;
}
protected Class resolveClass(ObjectStreamClass objClass)
throws IOException, ClassNotFoundException{ // Display Comment We override this method to make it compatible with our "MyInputStream", it read version number from the serialized data for each new encountered class descriptor.
this.version = readFloat(); return super.resolveClass(objClass); } } // Display Comment SimpleClass1 is example of old outdated class, while SimpleClass2 is latest class extended from SimpleClass1 where its getValue() method is overrides to add value by 100 upon returning result.
class SimpleClass1 implements Serializable{
static float version = 1.0f;
int value;
public SimpleClass1(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
class SimpleClass2 extends SimpleClass1{
static float version = 2.0f;
int value;
public SimpleClass2(int value){
super(0);
this.value = value;
}
public int getValue(){
return value+100;
}
}
public class AnnotateClassExample {
public static void main(String args[]){
try{
FileOutputStream f = new FileOutputStream("AnnotateClass.ser");
MyOutputStream out = new MyOutputStream(f);
SimpleClass1 simpleClass1 = new SimpleClass1(6); // Display Comment This is where the example come to life. We first create an instance of SimpleClass1 and try calling its getValue() method just to show that it return an expected unchanged value of 6, then serialize this outdated instance of SimpleClass1 to the OutputStream, by setting its version number "1.0" and write the object to the stream.
System.out.println("Before serialize simpleClass1 value:"+
simpleClass1.getValue());
out.setVersion(simpleClass1.version);
out.writeObject(simpleClass1);
SimpleClass2 simpleClass2 = new SimpleClass2(6); // Display Comment Then we create an instance of SimpleClass2, output its value to console just to see it is overrided the method from SimpleClass1, which increase the original value by 100. Since we initialize the SimpleClass2 with value of 6, it suppose to display 106 to the console by calling getValue() method.
System.out.println("Before serialize simpleClass2 value:"+
simpleClass2.getValue());
out.setVersion(simpleClass2.version);
out.writeObject(simpleClass2);
out.flush();
out.close();
FileInputStream f2 = new FileInputStream("AnnotateClass.ser");
MyInputStream in = new MyInputStream(f2); // Display Comment Now read back from the serialized data, note that the outdated SimpleClass1 are upgraded to its latest implementation - SimpleClass2. It is done internally in MyObjectInputStream.resolveObject() during deserialization. Even though we cast the first result of in.readObject() to SimpleClass1, but its structure is actually upgraded to SimpleClass2, you can see the result in the following console output. where both object now returning the same value, incrementing value by 100.
SimpleClass1 in_simpleClass1 = (SimpleClass1)in.readObject();
SimpleClass2 in_simpleClass2 = (SimpleClass2)in.readObject();
in.close();
System.out.println("After deserialized in_simpleClass1 value:"+
in_simpleClass1.getValue());
System.out.println("After deserialized in_simpleClass2 value:"+
in_simpleClass2.getValue()); // Display Comment Execute this example and you will see the following console output: Before serialize simpleClass1 value:6 Before serialize simpleClass2 value:106 After deserialized in_simpleClass1 value:106 After deserialized in_simpleClass2 value:106
}catch(Exception e){
System.out.println(e);
}
}
}
| |
| public void close () | Write remaining buffered to output stream and release any resources. |
|
Syntax
Exception
Description
Example | |
| public void defaultWriteObject () | Write non-static and non-transient fields of class to the stream. |
|
Syntax
Exception
Description | |
| protected void drain () | Write any buffered data to underlying output stream, but does not flush the stream. |
|
Syntax
Exception
Description | |
| protected final boolean enableReplaceObject (boolean enable) | By default, ObjectOutputStream does not allow replaceObject() to be overrides by subclass. This method must set to true if subclass of ObjectOutputStream is going to overrides replaceObject(). |
|
Syntax
Exception
Example | |
| public void flush () | This method write any remaining buffered bytes to underlying stream and flush it. |
|
Syntax
Exception
Description
Example | |
| protected Object replaceObject (Object obj) | Replace an object with another object during serialization. |
|
Syntax
Parameter
Exception
Description package com.geek.tutorials.io.ObjectOutputStream;
import java.io.*;
class AutoUpgradeOutputStream extends ObjectOutputStream {
AutoUpgradeOutputStream(OutputStream out) throws IOException, StreamCorruptedException{
super(out);
enableReplaceObject(true); // Display Comment AutoUpgradeOutputStream is subclass of ObjectOutputStream, enableReplaceObject() should set to true if we are overriding replaceObject() method, else nothing will happen in replaceObject();
}
protected Object replaceObject(Object obj){// Display Comment If the obj are instance of OldClass, we upgrade it to NewClass and return the new object, else do nothing and just return the obj.
if(obj instanceof OldClass){
return new NewClass(((OldClass)obj).getValue());
}
return obj;
}
}
class OldClass implements Serializable{ // Display Comment An old serializable class that will be replace by new class during serialization.
int value;
public OldClass(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
class NewClass extends OldClass{ // Display Comment An upgraded class that use to replace an old class during serialization.
int value;
public NewClass(int value){
super(0);
this.value = value;
}
public int getValue(){
return value+100; // Display Comment The only different of new class is getValue() method return value that added by 100.
}
}
public class ReplaceObjectExample {
public static void main(String args[]){
try{// Display Comment Open a new AutoUpgradeOutputStream and serialize OldClass into OutputStream, the OldClass will be upgrade to NewClass during serialization. Then flush the buffered data out to stream and close it to complete the serialization.
FileOutputStream f = new FileOutputStream("ReplaceObjectExample.ser");
ObjectOutputStream out = new AutoUpgradeOutputStream(f);
OldClass oldClass = new OldClass(20);
out.writeObject(oldClass);
out.flush();
out.close();
// Display Comment Read back the serialized object with ObjectInputStream.readObject(). When the program use getValue() output data to console, you will see that the value of 20 has increase by 100 which is 120 now, it mean that the OldClass has successfully upgraded OldClass to NewClass with replaceObject during serialization.
FileInputStream f2 = new FileInputStream("ReplaceObjectExample.ser");
ObjectInput in = new ObjectInputStream(f2);
NewClass updatedClass = (NewClass)in.readObject();
System.out.println("value: "+updatedClass.getValue());
}catch(Exception e){
System.out.println(e);
}
}
}
| |
| public void reset () | Reset the state of the object output stream |
|
Syntax
Exception
Description package com.geek.tutorials.io.ObjectOutputStream;
import java.io.*;
import java.util.Date;
class TestAnnotateClassOutputStream extends ObjectOutputStream{
public TestAnnotateClassOutputStream(OutputStream out) throws IOException{
super(out);
}
protected void annotateClass(Class cl) throws IOException{// Display Comment Write current timestamp during serialization. annotateClass() will only invoke if current object's class is first time writing into this stream, subsequence object of the same class will not causes this method to be invoke. However, you may force annotateClass to get invoke again by calling reset() before you serialize another object of same class into the output stream.
writeLong((new Date()).getTime());
}
}
class TestAnnotateClassInputStream extends ObjectInputStream{
public TestAnnotateClassInputStream(InputStream in)throws
IOException, StreamCorruptedException{
super(in);
}
protected Class resolveClass(ObjectStreamClass osc)throws
IOException, ClassNotFoundException{// Display Comment This method will only be invoke once for each type of object's class in the stream, any subsequence object of same class will not causes this method to be invoke agian. However, if the input stream encounter reset marker in the stream, it will invoke resolveClass() again for all the object of same class that had been loaded previously from the stream.
System.out.println("Timestamp:"+readLong());
return super.resolveClass(osc);
}
}
class ResetTestClass implements Serializable{// Display Comment This is just simple test class for this serialization example
String text;
public ResetTestClass(String text){
this.text = text;
}
public String toString(){
return text;
}
}
public class ResetExample {
public static void main(String args[]){
try{
FileOutputStream f = new FileOutputStream("ResetExample.ser");
TestAnnotateClassOutputStream out =
new TestAnnotateClassOutputStream(f);
// Display Comment Serialize 3 ResetTestClass into the TestAnnotateClassOutputStream. TestAnnotateClassOutputStream will record timestamp during serialization, it only record timestamp for the object's class that are first time serialize in this OutputStream, however you can force the TestAnnotateClassOutputStream to record subsequence object of same class by calling reset() method before serializing next object.
ResetTestClass simpleObj = new ResetTestClass("1st test string obj");
ResetTestClass simpleObj2 = new ResetTestClass("2nd test string obj");
ResetTestClass simpleObj3 = new ResetTestClass("3rd test string obj");
out.writeObject(simpleObj);// Display Comment For the first simpleObj being serialize, annotateClass() will be invoke internally in TestAnnotateClassOutputStream, which record the serialization timestamp in the output stream.
out.reset();// Display Comment However, if we call reset() method at this point. The class descriptor state will be clear and next object of the same class will causes annotateClass() to be invoke again, which record the timestamp again.
out.writeObject(simpleObj2); out.writeObject(simpleObj3);// Display Comment For simpleObj3 we did not call reset() method, just to show that without calling reset() method, annotateClass() does not get invoke agian. Run this example and you will see the following result output to console:
Timestamp:1183710134578 The timestamp may vary depend on what time you running this example, note that before the output "2nd test string obj" and "3rd test string obj", there is no timestamp. This is because reset() never call at that point during serialization. Therefore annotateClass() never invoke at that point, and also during deserialization reset marker do not exist at that point and never causes resolveClass() to be invoke too. out.flush();
out.close();
FileInputStream f2 = new FileInputStream("ResetExample.ser");
TestAnnotateClassInputStream in = new TestAnnotateClassInputStream(f2);
Object obj = in.readObject();
System.out.println(obj);
obj = in.readObject();
System.out.println(obj);
obj = in.readObject();
System.out.println(obj);
in.close();
}catch(Exception e){
System.out.println(e);
}
}
}
| |
| public void write () | This method write one or more bytes to underlying output stream. |
|
Syntax
Exception | |
| public void writeBoolean (boolean value) | Writes a boolean value to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeByte (int value) | Writes a byte value to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeBytes (String str) | Writes string in sequence of bytes to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeChar (int value) | Writes char to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeChars (String str) | Writes string in sequence of chars to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeDouble (double value) | Writes double to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeFloat (float value) | Writes float to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeInt (int value) | Writes int to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeLong (long value) | Writes long to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public final void writeObject (Object obj) | Writes an object to object output stream |
|
Syntax
Parameter
Exception
Example | |
| public void writeShort (int value) | Writes short to object output stream |
|
Syntax
Parameter
Exception
Example | |
| protected void writeStreamHeader () | Subclass can override this method to write additional header data into output stream |
|
Syntax IOException - If error occurs while writing data to underlying output stream. | |
| public void writeUTF (String str) | Writes a String as primitive data into output stream |
|
Syntax
Parameter
Exception
Example | |
package com.geek.tutorials.io.ObjectOutputStream;
import java.io.*;
import com.geek.tutorials.io.serializable.Class1;
public class WritePrimitiveExample {
public static void main(String arg[]){
try{
FileOutputStream f = new FileOutputStream("WritePrimiteExample.ser");
ObjectOutputStream out = new ObjectOutputStream(f);
out.writeBoolean(true); // writes a boolean
out.writeByte(2); // writes a byte
out.writeBytes("34"); // writes a bytes
out.writeChar('D'); // writes a char
out.writeChars("56"); // writes a chars
out.writeDouble(6.0); // writes a double
out.writeFloat(7.0f); // writes a float
out.writeInt(8); // writes a int
out.writeLong(999999999); // writes a long
out.writeShort(10); // writes a short
out.flush();
out.close();
FileInputStream f2 = new FileInputStream("WritePrimiteExample.ser");
ObjectInputStream in = new ObjectInputStream(f2);
boolean boolValue = in.readBoolean(); // read a boolean
byte byteValue = in.readByte(); // read a byte
int bytesValue = in.readByte(); // read first byte from bytes
int bytesValue2 = in.readByte(); // read second byte from bytes
char charValue = in.readChar(); // read a char
char chars1 = in.readChar(); // read first char from chars
char chars2 = in.readChar(); // read second char from chars
double doubleValue = in.readDouble(); // read a double
float floatValue = in.readFloat(); // read a float
int intValue = in.readInt(); // read a int
long longValue = in.readLong(); // read a long
short shortValue = in.readShort(); // read a short
in.close();
}catch(Exception e){
System.out.println(e);
}
}
}