Contents | Previous | Next | JavaTM Object Serialization Specification |
The stream format satisfies the following design goals:
A basic structure is needed to represent objects in a stream. Each attribute of the object needs to be represented: its classes, its fields, and data written and later read by class-specific methods. The representation of objects in the stream can be described with a grammar. There are special representations for null objects, new objects, classes, arrays, strings, and back references to any object already in the stream. Each object written to the stream is assigned a handle that is used to refer back to the object. Handles are assigned sequentially starting from 0x7E0000. The handles restart at 0x7E0000 when the stream is reset.
A class object is represented by the following:
ObjectStreamClass
object.
An ObjectStreamClass
object for a Class that is not a dynamic proxy class is represented by the following:
w
riteObject
methodLjava/lang/Object;
”) as specified in section 4.3.2 of The Java™ Virtual Machine Specification, Second Edition.annotateClass
methodObjectStreamClass
of its supertype (null if the superclass is not serializable)
An ObjectStreamClass
object for a dynamic proxy class is represented by the following:
getInterfaces
method on the Class object.annotateProxyClass
method.java.lang.reflect.Proxy
.
The representation of String
objects depends on the length of the UTF encoded string. If the UTF encoding of the given String
is less than 65536 bytes in length, the String
is written in the standard Java UTF-8 format. Starting with the Java™ 2 SDK, Standard Edition, v1.3, strings for which the UTF encoding length is greater than or equal to 65536 bytes are written in a variant “long” UTF format. The “long” UTF format is identical to the standard Java UTF-8 format, except that it uses 8 bytes to write the length of the UTF string, instead of 2 bytes. The typecode preceding the String
in the serialization stream indicates which format was used to write the String
.
Arrays are represented by the following:
ObjectStreamClass
object.New objects in the stream are represented by the following:
writeObject
/readObject
methods, there may be optional objects and/or block-data records of primitive types written by the writeObject
method followed by an endBlockData
code.
All primitive data written by classes is buffered and wrapped in block-data records, regardless if the data is written to the stream within a writeObject
method or written directly to the stream from outside a writeObject
method. This data can only be read by the corresponding readObject
methods or be read directly from the stream. Objects written by the writeObject
method terminate any previous block-data record and are written either as regular objects or null or back references, as appropriate. The block-data records allow error recovery to discard any optional data. When called from within a class, the stream can discard any data or objects until the endBlockData
.
It was necessary to make a change to the serialization stream format in JDK™ 1.2 that is not backwards compatible to all minor releases of JDK™ 1.1. To provide for cases where backwards compatibility is required, a capability has been added to indicate what PROTOCOL_VERSION
to use when writing a serialization stream. The method ObjectOutputStream.useProtocolVersion
takes as a parameter the protocol version to use to write the serialization stream.
The Stream Protocol Versions are as follows:
ObjectStreamConstants.PROTOCOL_VERSION_1
Indicates the initial stream format.
ObjectStreamConstants.PROTOCOL_VERSION_2
Indicates the new external data format. Primitive data is written in block data mode and is terminated with TC_ENDBLOCKDATA
.
Block data boundaries have been standardized. Primitive data written in block data mode is normalized to not exceed 1024 byte chunks. The benefit of this change was to tighten the specification of serialized data format within the stream. This change is fully backward and forward compatible.
JDK™ 1.2 defaults to writing PROTOCOL_VERSION_2
.
JDK™ 1.1 defaults to writing PROTOCOL_VERSION_1
.
JDK™ 1.1.7 and greater can read both versions.
Releases prior to JDK™ 1.1.7 can only read PROTOCOL_VERSION_1
.
The table below contains the grammar for the stream format. Nonterminal symbols are shown in italics. Terminal symbols in a fixed width font
. Definitions of nonterminals are followed by a “:”. The definition is followed by one or more alternatives, each on a separate line. The following table describes the notation:
Note that the symbol (long-utf) is used to designate a string written in “long” UTF format. For details, refer to Section 6.2 "Stream Elements”.
A Serialized stream is represented by any stream satisfying the stream rule.
stream: magic version contentscontents: content contents contentcontent: object blockdataobject: newObject newClass newArray newString newClassDesc prevObject nullReference exception TC_RESETnewClass: TC_CLASS classDesc newHandleclassDesc: newClassDesc nullReference (ClassDesc)prevObject // an object required to be of type // ClassDescsuperClassDesc: classDescnewClassDesc: TC_CLASSDESC className serialVersionUID newHandle classDescInfo TC_PROXYCLASSDESC newHandle proxyClassDescInfoclassDescInfo: classDescFlags fields classAnnotation superClassDescclassName: (utf)serialVersionUID: (long)classDescFlags: (byte) // Defined in Terminal Symbols and // ConstantsproxyClassDescInfo: (int)<count> proxyInterfaceName[count] classAnnotation superClassDescproxyInterfaceName: (utf)fields: (short)<count> fieldDesc[count]fieldDesc: primitiveDesc objectDescprimitiveDesc: prim_typecode fieldNameobjectDesc: obj_typecode fieldName className1fieldName: (utf)className1: (String)object // String containing the field's type, // in field descriptor formatclassAnnotation: endBlockData contents endBlockData // contents written by annotateClassprim_typecode: `B' // byte `C' // char `D' // double `F' // float `I' // integer `J' // long `S' // short `Z' // booleanobj_typecode: `[` // array `L' // objectnewArray: TC_ARRAY classDesc newHandle (int)<size> values[size]newObject: TC_OBJECT classDesc newHandle classdata[] // data for each classclassdata: nowrclass // SC_SERIALIZABLE & classDescFlag && // !(SC_WRITE_METHOD & classDescFlags) wrclass objectAnnotation // SC_SERIALIZABLE & classDescFlag && // SC_WRITE_METHOD & classDescFlags externalContents // SC_EXTERNALIZABLE & classDescFlag && // !(SC_BLOCKDATA & classDescFlags objectAnnotation // SC_EXTERNALIZABLE & classDescFlag&& // SC_BLOCKDATA & classDescFlagsnowrclass: values // fields in order of class descriptorwrclass: nowrclassobjectAnnotation: endBlockData contents endBlockData // contents written by writeObject // or writeExternal PROTOCOL_VERSION_2.blockdata: blockdatashort blockdatalongblockdatashort: TC_BLOCKDATA (unsigned byte)<size> (byte)[size]blockdatalong: TC_BLOCKDATALONG (int)<size> (byte)[size]endBlockData : TC_ENDBLOCKDATAexternalContent: // Only parseable by readExternal ( bytes) // primitive data objectexternalContents: // externalContent written by externalContent // writeExternal in PROTOCOL_VERSION_1. externalContents externalContentnewString: TC_STRING newHandle (utf) TC_LONGSTRING newHandle (long-utf)prevObject TC_REFERENCE (int)handlenullReference TC_NULLexception: TC_EXCEPTION reset (Throwable)object resetmagic: STREAM_MAGICversion STREAM_VERSIONvalues: // The size and types are described by the // classDesc for the current objectnewHandle: // The next number in sequence is assigned // to the object being serialized or deserializedreset: // The set of known objects is discarded // so the objects of the exception do not // overlap with the previously sent objects // or with objects that may be sent after // the exception
The following symbols in java.io.ObjectStreamConstants
define the terminal and constant values expected in a stream.
final static short STREAM_MAGIC = (short)0xaced; final static short STREAM_VERSION = 5; final static byte TC_NULL = (byte)0x70; final static byte TC_REFERENCE = (byte)0x71; final static byte TC_CLASSDESC = (byte)0x72; final static byte TC_OBJECT = (byte)0x73; final static byte TC_STRING = (byte)0x74; final static byte TC_ARRAY = (byte)0x75; final static byte TC_CLASS = (byte)0x76; final static byte TC_BLOCKDATA = (byte)0x77; final static byte TC_ENDBLOCKDATA = (byte)0x78; final static byte TC_RESET = (byte)0x79; final static byte TC_BLOCKDATALONG = (byte)0x7A; final static byte TC_EXCEPTION = (byte)0x7B; final static byte TC_LONGSTRING = (byte) 0x7C; final static byte TC_PROXYCLASSDESC = (byte) 0x7D; final static int baseWireHandle = 0x7E0000;
The flag byte classDescFlags
may include values of
final static byte SC_WRITE_METHOD = 0x01; //if SC_SERIALIZABLE final static byte SC_BLOCK_DATA = 0x08; //if SC_EXTERNALIZABLE final static byte SC_SERIALIZABLE = 0x02; final static byte SC_EXTERNALIZABLE = 0x04;
The flag SC_WRITE_METHOD
is set if the Serializable class writing the stream had a writeObject
method that may have written additional data to the stream. In this case a TC_ENDBLOCKDATA
marker is always expected to terminate the data for that class.
The flag SC_BLOCKDATA
is set if the Externalizable
class is written into the stream using STREAM_PROTOCOL_2
. By default, this is the protocol used to write Externalizable
objects into the stream in JDK™ 1.2. JDK™ 1.1 writes STREAM_PROTOCOL_1
.
The flag SC_SERIALIZABLE
is set if the class that wrote the stream extended java.io.Serializable
but not java.io.Externalizable
, the class reading the stream must also extend java.io.Serializable
and the default serialization mechanism is to be used.
The flag SC_EXTERNALIZABLE
is set if the class that wrote the stream extended java.io.Externalizable
, the class reading the data must also extend Externalizable
and the data will be read using its writeExternal
and readExternal
methods.
Consider the case of an original class and two instances in a linked list:
class List implements java.io.Serializable { int value; List next; public static void main(String[] args) { try { List list1 = new List(); List list2 = new List(); list1.value = 17; list1.next = list2; list2.value = 19; list2.next = null; ByteArrayOutputStream o = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(o); out.writeObject(list1); out.writeObject(list2); out.flush(); ... } catch (Exception ex) { ex.printStackTrace(); } } }
The resulting stream contains:
00: ac ed 00 05 73 72 00 04 4c 69 73 74 69 c8 8a 15 >....sr..Listi...< 10: 40 16 ae 68 02 00 02 49 00 05 76 61 6c 75 65 4c >Z......I..valueL< 20: 00 04 6e 65 78 74 74 00 06 4c 4c 69 73 74 3b 78 >..nextt..LList;x< 30: 70 00 00 00 11 73 71 00 7e 00 00 00 00 00 13 70 >p....sq.~......p< 40: 71 00 7e 00 03 >q.~..<
Contents | Previous | Next | JavaTM Object Serialization Specification |
Copyright © 2003 Sun Microsystems, Inc. All rights reserved.