< prev index next >

src/java.base/share/classes/java/io/ObjectOutputStream.java

Print this page

  19  * 2 along with this work; if not, write to the Free Software Foundation,
  20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21  *
  22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  23  * or visit www.oracle.com if you need additional information or have any
  24  * questions.
  25  */
  26 
  27 package java.io;
  28 
  29 import java.util.ArrayList;
  30 import java.util.Arrays;
  31 import java.util.List;
  32 import java.util.Objects;
  33 import java.util.StringJoiner;
  34 
  35 import jdk.internal.util.ByteArray;
  36 import jdk.internal.access.JavaLangAccess;
  37 import jdk.internal.access.SharedSecrets;
  38 


  39 import static jdk.internal.util.ModifiedUtf.putChar;
  40 import static jdk.internal.util.ModifiedUtf.utfLen;
  41 
  42 /**
  43  * An ObjectOutputStream writes primitive data types and graphs of Java objects
  44  * to an OutputStream.  The objects can be read (reconstituted) using an
  45  * ObjectInputStream.  Persistent storage of objects can be accomplished by
  46  * using a file for the stream.  If the stream is a network socket stream, the
  47  * objects can be reconstituted on another host or in another process.
  48  *
  49  * <p>Only objects that support the java.io.Serializable interface can be
  50  * written to streams.  The class of each serializable object is encoded
  51  * including the class name and signature of the class, the values of the
  52  * object's fields and arrays, and the closure of any other objects referenced
  53  * from the initial objects.
  54  *
  55  * <p>The method writeObject is used to write an object to the stream.  Any
  56  * object, including Strings and arrays, is written with writeObject. Multiple
  57  * objects or primitives can be written to the stream.  The objects must be
  58  * read back from the corresponding ObjectInputstream with the same types and

 113  * implement the java.io.Serializable interface.  Subclasses of Objects that
 114  * are not serializable can be serializable. In this case the non-serializable
 115  * class must have a no-arg constructor to allow its fields to be initialized.
 116  * In this case it is the responsibility of the subclass to save and restore
 117  * the state of the non-serializable class. It is frequently the case that the
 118  * fields of that class are accessible (public, package, or protected) or that
 119  * there are get and set methods that can be used to restore the state.
 120  *
 121  * <p>Serialization of an object can be prevented by implementing writeObject
 122  * and readObject methods that throw the NotSerializableException.  The
 123  * exception will be caught by the ObjectOutputStream and abort the
 124  * serialization process.
 125  *
 126  * <p>Implementing the Externalizable interface allows the object to assume
 127  * complete control over the contents and format of the object's serialized
 128  * form.  The methods of the Externalizable interface, writeExternal and
 129  * readExternal, are called to save and restore the objects state.  When
 130  * implemented by a class they can write and read their own state using all of
 131  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
 132  * the objects to handle any versioning that occurs.






 133  *
 134  * <p>Enum constants are serialized differently than ordinary serializable or
 135  * externalizable objects.  The serialized form of an enum constant consists
 136  * solely of its name; field values of the constant are not transmitted.  To
 137  * serialize an enum constant, ObjectOutputStream writes the string returned by
 138  * the constant's name method.  Like other serializable or externalizable
 139  * objects, enum constants can function as the targets of back references
 140  * appearing subsequently in the serialization stream.  The process by which
 141  * enum constants are serialized cannot be customized; any class-specific
 142  * writeObject and writeReplace methods defined by enum types are ignored
 143  * during serialization.  Similarly, any serialPersistentFields or
 144  * serialVersionUID field declarations are also ignored--all enum types have a
 145  * fixed serialVersionUID of 0L.
 146  *
 147  * <p>Primitive data, excluding serializable fields and externalizable data, is
 148  * written to the ObjectOutputStream in block-data records. A block data record
 149  * is composed of a header and data. The block data header consists of a marker
 150  * and the number of bytes to follow the header.  Consecutive primitive data
 151  * writes are merged into one block-data record.  The blocking factor used for
 152  * a block-data record will be 1024 bytes.  Each block-data record will be
 153  * filled up to 1024 bytes, or be written whenever there is a termination of
 154  * block-data mode.  Calls to the ObjectOutputStream methods writeObject,
 155  * defaultWriteObject and writeFields initially terminate any existing
 156  * block-data record.
 157  *

 158  * <p>Records are serialized differently than ordinary serializable or externalizable
 159  * objects, see <a href="ObjectInputStream.html#record-serialization">record serialization</a>.
 160  *


























 161  * @spec serialization/index.html Java Object Serialization Specification
 162  * @author      Mike Warres
 163  * @author      Roger Riggs
 164  * @see java.io.DataOutput
 165  * @see java.io.ObjectInputStream
 166  * @see java.io.Serializable
 167  * @see java.io.Externalizable
 168  * @see <a href="{@docRoot}/../specs/serialization/output.html">
 169  *      <cite>Java Object Serialization Specification,</cite> Section 2, "Object Output Classes"</a>
 170  * @since       1.1
 171  */
 172 public class ObjectOutputStream
 173     extends OutputStream implements ObjectOutput, ObjectStreamConstants
 174 {
 175     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 176 
 177     /** filter stream for handling block data conversion */
 178     private final BlockDataOutputStream bout;
 179     /** obj -> wire handle map */
 180     private final HandleTable handles;

 287             case PROTOCOL_VERSION_1:
 288             case PROTOCOL_VERSION_2:
 289                 protocol = version;
 290                 break;
 291 
 292             default:
 293                 throw new IllegalArgumentException(
 294                     "unknown version: " + version);
 295         }
 296     }
 297 
 298     /**
 299      * Write the specified object to the ObjectOutputStream.  The class of the
 300      * object, the signature of the class, and the values of the non-transient
 301      * and non-static fields of the class and all of its supertypes are
 302      * written.  Default serialization for a class can be overridden using the
 303      * writeObject and the readObject methods.  Objects referenced by this
 304      * object are written transitively so that a complete equivalent graph of
 305      * objects can be reconstructed by an ObjectInputStream.
 306      *



 307      * <p>Exceptions are thrown for problems with the OutputStream and for
 308      * classes that should not be serialized.  All exceptions are fatal to the
 309      * OutputStream, which is left in an indeterminate state, and it is up to
 310      * the caller to ignore or recover the stream state.
 311      *
 312      * @throws  InvalidClassException Something is wrong with a class used by
 313      *          serialization.
 314      * @throws  NotSerializableException Some object to be serialized does not
 315      *          implement the java.io.Serializable interface.
 316      * @throws  IOException Any exception thrown by the underlying
 317      *          OutputStream.
 318      */
 319     public final void writeObject(Object obj) throws IOException {
 320         if (enableOverride) {
 321             writeObjectOverride(obj);
 322             return;
 323         }
 324         try {
 325             writeObject0(obj, false);
 326         } catch (IOException ex) {

1295     private void writeOrdinaryObject(Object obj,
1296                                      ObjectStreamClass desc,
1297                                      boolean unshared)
1298         throws IOException
1299     {
1300         if (extendedDebugInfo) {
1301             debugInfoStack.push(
1302                 (depth == 1 ? "root " : "") + "object (class \"" +
1303                 obj.getClass().getName() + "\", " + obj.toString() + ")");
1304         }
1305         try {
1306             desc.checkSerialize();
1307 
1308             bout.writeByte(TC_OBJECT);
1309             writeClassDesc(desc, false);
1310             handles.assign(unshared ? null : obj);
1311 
1312             if (desc.isRecord()) {
1313                 writeRecordData(obj, desc);
1314             } else if (desc.isExternalizable() && !desc.isProxy()) {



1315                 writeExternalData((Externalizable) obj);
1316             } else {
1317                 writeSerialData(obj, desc);
1318             }
1319         } finally {
1320             if (extendedDebugInfo) {
1321                 debugInfoStack.pop();
1322             }
1323         }
1324     }
1325 
1326     /**
1327      * Writes externalizable data of given object by invoking its
1328      * writeExternal() method.
1329      */
1330     private void writeExternalData(Externalizable obj) throws IOException {
1331         PutFieldImpl oldPut = curPut;
1332         curPut = null;
1333 
1334         if (extendedDebugInfo) {

1343                 bout.setBlockDataMode(true);
1344                 obj.writeExternal(this);
1345                 bout.setBlockDataMode(false);
1346                 bout.writeByte(TC_ENDBLOCKDATA);
1347             }
1348         } finally {
1349             curContext = oldContext;
1350             if (extendedDebugInfo) {
1351                 debugInfoStack.pop();
1352             }
1353         }
1354 
1355         curPut = oldPut;
1356     }
1357 
1358     /** Writes the record component values for the given record object. */
1359     private void writeRecordData(Object obj, ObjectStreamClass desc)
1360         throws IOException
1361     {
1362         assert obj.getClass().isRecord();
1363         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1364         if (slots.length != 1) {
1365             throw new InvalidClassException(
1366                     "expected a single record slot length, but found: " + slots.length);
1367         }
1368 
1369         defaultWriteFields(obj, desc);  // #### seems unnecessary to use the accessors
1370     }
1371 
1372     /**
1373      * Writes instance data for each serializable class of given object, from
1374      * superclass to subclass.
1375      */
1376     private void writeSerialData(Object obj, ObjectStreamClass desc)
1377         throws IOException
1378     {
1379         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1380         for (int i = 0; i < slots.length; i++) {
1381             ObjectStreamClass slotDesc = slots[i].desc;
1382             if (slotDesc.hasWriteObjectMethod()) {
1383                 PutFieldImpl oldPut = curPut;
1384                 curPut = null;
1385                 SerialCallbackContext oldContext = curContext;
1386 
1387                 if (extendedDebugInfo) {
1388                     debugInfoStack.push(
1389                         "custom writeObject data (class \"" +
1390                         slotDesc.getName() + "\")");
1391                 }
1392                 try {
1393                     curContext = new SerialCallbackContext(obj, slotDesc);
1394                     bout.setBlockDataMode(true);
1395                     slotDesc.invokeWriteObject(obj, this);
1396                     bout.setBlockDataMode(false);
1397                     bout.writeByte(TC_ENDBLOCKDATA);
1398                 } finally {
1399                     curContext.setUsed();
1400                     curContext = oldContext;
1401                     if (extendedDebugInfo) {

  19  * 2 along with this work; if not, write to the Free Software Foundation,
  20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21  *
  22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  23  * or visit www.oracle.com if you need additional information or have any
  24  * questions.
  25  */
  26 
  27 package java.io;
  28 
  29 import java.util.ArrayList;
  30 import java.util.Arrays;
  31 import java.util.List;
  32 import java.util.Objects;
  33 import java.util.StringJoiner;
  34 
  35 import jdk.internal.util.ByteArray;
  36 import jdk.internal.access.JavaLangAccess;
  37 import jdk.internal.access.SharedSecrets;
  38 
  39 import static java.io.ObjectInputStream.TRACE;
  40 
  41 import static jdk.internal.util.ModifiedUtf.putChar;
  42 import static jdk.internal.util.ModifiedUtf.utfLen;
  43 
  44 /**
  45  * An ObjectOutputStream writes primitive data types and graphs of Java objects
  46  * to an OutputStream.  The objects can be read (reconstituted) using an
  47  * ObjectInputStream.  Persistent storage of objects can be accomplished by
  48  * using a file for the stream.  If the stream is a network socket stream, the
  49  * objects can be reconstituted on another host or in another process.
  50  *
  51  * <p>Only objects that support the java.io.Serializable interface can be
  52  * written to streams.  The class of each serializable object is encoded
  53  * including the class name and signature of the class, the values of the
  54  * object's fields and arrays, and the closure of any other objects referenced
  55  * from the initial objects.
  56  *
  57  * <p>The method writeObject is used to write an object to the stream.  Any
  58  * object, including Strings and arrays, is written with writeObject. Multiple
  59  * objects or primitives can be written to the stream.  The objects must be
  60  * read back from the corresponding ObjectInputstream with the same types and

 115  * implement the java.io.Serializable interface.  Subclasses of Objects that
 116  * are not serializable can be serializable. In this case the non-serializable
 117  * class must have a no-arg constructor to allow its fields to be initialized.
 118  * In this case it is the responsibility of the subclass to save and restore
 119  * the state of the non-serializable class. It is frequently the case that the
 120  * fields of that class are accessible (public, package, or protected) or that
 121  * there are get and set methods that can be used to restore the state.
 122  *
 123  * <p>Serialization of an object can be prevented by implementing writeObject
 124  * and readObject methods that throw the NotSerializableException.  The
 125  * exception will be caught by the ObjectOutputStream and abort the
 126  * serialization process.
 127  *
 128  * <p>Implementing the Externalizable interface allows the object to assume
 129  * complete control over the contents and format of the object's serialized
 130  * form.  The methods of the Externalizable interface, writeExternal and
 131  * readExternal, are called to save and restore the objects state.  When
 132  * implemented by a class they can write and read their own state using all of
 133  * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
 134  * the objects to handle any versioning that occurs.
 135  * Value classes implementing {@link Externalizable} cannot be serialized
 136  * or deserialized, the value object is immutable and the state cannot be restored.
 137  * Use {@link Serializable} {@code writeReplace} to delegate to another serializable
 138  * object such as a record.
 139  *
 140  * Value objects cannot be {@code java.io.Externalizable}.
 141  *
 142  * <p>Enum constants are serialized differently than ordinary serializable or
 143  * externalizable objects.  The serialized form of an enum constant consists
 144  * solely of its name; field values of the constant are not transmitted.  To
 145  * serialize an enum constant, ObjectOutputStream writes the string returned by
 146  * the constant's name method.  Like other serializable or externalizable
 147  * objects, enum constants can function as the targets of back references
 148  * appearing subsequently in the serialization stream.  The process by which
 149  * enum constants are serialized cannot be customized; any class-specific
 150  * writeObject and writeReplace methods defined by enum types are ignored
 151  * during serialization.  Similarly, any serialPersistentFields or
 152  * serialVersionUID field declarations are also ignored--all enum types have a
 153  * fixed serialVersionUID of 0L.
 154  *
 155  * <p>Primitive data, excluding serializable fields and externalizable data, is
 156  * written to the ObjectOutputStream in block-data records. A block data record
 157  * is composed of a header and data. The block data header consists of a marker
 158  * and the number of bytes to follow the header.  Consecutive primitive data
 159  * writes are merged into one block-data record.  The blocking factor used for
 160  * a block-data record will be 1024 bytes.  Each block-data record will be
 161  * filled up to 1024 bytes, or be written whenever there is a termination of
 162  * block-data mode.  Calls to the ObjectOutputStream methods writeObject,
 163  * defaultWriteObject and writeFields initially terminate any existing
 164  * block-data record.
 165  *
 166  * <a id="record-serialization"></a>
 167  * <p>Records are serialized differently than ordinary serializable or externalizable
 168  * objects, see <a href="ObjectInputStream.html#record-serialization">record serialization</a>.
 169  *
 170  * <a id="valueclass-serialization"></a>
 171  * <p>Value classes are {@linkplain Serializable} through the use of the serialization proxy pattern.
 172  * The serialization protocol does not support a standard serialized form for value classes.
 173  * The value class delegates to a serialization proxy by supplying an alternate
 174  * record or object to be serialized instead of the value class.
 175  * When the proxy is deserialized it re-constructs the value object and returns the value object.
 176  * For example,
 177  * {@snippet lang="java" :
 178  * value class ZipCode implements Serializable {    // @highlight substring="value class"
 179  *     private static final long serialVersionUID = 1L;
 180  *     private int zipCode;
 181  *     public ZipCode(int zip) { this.zipCode = zip; }
 182  *     public int zipCode() { return zipCode; }
 183  *
 184  *     public Object writeReplace() {    // @highlight substring="writeReplace"
 185  *         return new ZipCodeProxy(zipCode);
 186  *     }
 187  *
 188  *     private record ZipCodeProxy(int zipCode) implements Serializable {
 189  *         public Object readResolve() {    // @highlight substring="readResolve"
 190  *             return new ZipCode(zipCode);
 191  *         }
 192  *     }
 193  * }
 194  * }
 195  *
 196  * @spec serialization/index.html Java Object Serialization Specification
 197  * @author      Mike Warres
 198  * @author      Roger Riggs
 199  * @see java.io.DataOutput
 200  * @see java.io.ObjectInputStream
 201  * @see java.io.Serializable
 202  * @see java.io.Externalizable
 203  * @see <a href="{@docRoot}/../specs/serialization/output.html">
 204  *      <cite>Java Object Serialization Specification,</cite> Section 2, "Object Output Classes"</a>
 205  * @since       1.1
 206  */
 207 public class ObjectOutputStream
 208     extends OutputStream implements ObjectOutput, ObjectStreamConstants
 209 {
 210     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 211 
 212     /** filter stream for handling block data conversion */
 213     private final BlockDataOutputStream bout;
 214     /** obj -> wire handle map */
 215     private final HandleTable handles;

 322             case PROTOCOL_VERSION_1:
 323             case PROTOCOL_VERSION_2:
 324                 protocol = version;
 325                 break;
 326 
 327             default:
 328                 throw new IllegalArgumentException(
 329                     "unknown version: " + version);
 330         }
 331     }
 332 
 333     /**
 334      * Write the specified object to the ObjectOutputStream.  The class of the
 335      * object, the signature of the class, and the values of the non-transient
 336      * and non-static fields of the class and all of its supertypes are
 337      * written.  Default serialization for a class can be overridden using the
 338      * writeObject and the readObject methods.  Objects referenced by this
 339      * object are written transitively so that a complete equivalent graph of
 340      * objects can be reconstructed by an ObjectInputStream.
 341      *
 342      * <p>Serialization and deserialization of value classes is described in
 343      * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
 344      *
 345      * <p>Exceptions are thrown for problems with the OutputStream and for
 346      * classes that should not be serialized.  All exceptions are fatal to the
 347      * OutputStream, which is left in an indeterminate state, and it is up to
 348      * the caller to ignore or recover the stream state.
 349      *
 350      * @throws  InvalidClassException Something is wrong with a class used by
 351      *          serialization.
 352      * @throws  NotSerializableException Some object to be serialized does not
 353      *          implement the java.io.Serializable interface.
 354      * @throws  IOException Any exception thrown by the underlying
 355      *          OutputStream.
 356      */
 357     public final void writeObject(Object obj) throws IOException {
 358         if (enableOverride) {
 359             writeObjectOverride(obj);
 360             return;
 361         }
 362         try {
 363             writeObject0(obj, false);
 364         } catch (IOException ex) {

1333     private void writeOrdinaryObject(Object obj,
1334                                      ObjectStreamClass desc,
1335                                      boolean unshared)
1336         throws IOException
1337     {
1338         if (extendedDebugInfo) {
1339             debugInfoStack.push(
1340                 (depth == 1 ? "root " : "") + "object (class \"" +
1341                 obj.getClass().getName() + "\", " + obj.toString() + ")");
1342         }
1343         try {
1344             desc.checkSerialize();
1345 
1346             bout.writeByte(TC_OBJECT);
1347             writeClassDesc(desc, false);
1348             handles.assign(unshared ? null : obj);
1349 
1350             if (desc.isRecord()) {
1351                 writeRecordData(obj, desc);
1352             } else if (desc.isExternalizable() && !desc.isProxy()) {
1353                 if (desc.isValue())
1354                     throw new InvalidClassException("Externalizable not valid for value class "
1355                             + desc.forClass().getName());
1356                 writeExternalData((Externalizable) obj);
1357             } else {
1358                 writeSerialData(obj, desc);
1359             }
1360         } finally {
1361             if (extendedDebugInfo) {
1362                 debugInfoStack.pop();
1363             }
1364         }
1365     }
1366 
1367     /**
1368      * Writes externalizable data of given object by invoking its
1369      * writeExternal() method.
1370      */
1371     private void writeExternalData(Externalizable obj) throws IOException {
1372         PutFieldImpl oldPut = curPut;
1373         curPut = null;
1374 
1375         if (extendedDebugInfo) {

1384                 bout.setBlockDataMode(true);
1385                 obj.writeExternal(this);
1386                 bout.setBlockDataMode(false);
1387                 bout.writeByte(TC_ENDBLOCKDATA);
1388             }
1389         } finally {
1390             curContext = oldContext;
1391             if (extendedDebugInfo) {
1392                 debugInfoStack.pop();
1393             }
1394         }
1395 
1396         curPut = oldPut;
1397     }
1398 
1399     /** Writes the record component values for the given record object. */
1400     private void writeRecordData(Object obj, ObjectStreamClass desc)
1401         throws IOException
1402     {
1403         assert obj.getClass().isRecord();
1404         List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
1405         if (slots.size() != 1) {
1406             throw new InvalidClassException(
1407                     "expected a single record slot length, but found: " + slots.size());
1408         }
1409 
1410         defaultWriteFields(obj, desc);  // #### seems unnecessary to use the accessors
1411     }
1412 
1413     /**
1414      * Writes instance data for each serializable class of given object, from
1415      * superclass to subclass.
1416      */
1417     private void writeSerialData(Object obj, ObjectStreamClass desc)
1418         throws IOException
1419     {
1420        List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
1421         for (int i = 0; i < slots.size(); i++) {
1422             ObjectStreamClass slotDesc = slots.get(i).desc;
1423             if (slotDesc.hasWriteObjectMethod()) {
1424                 PutFieldImpl oldPut = curPut;
1425                 curPut = null;
1426                 SerialCallbackContext oldContext = curContext;
1427 
1428                 if (extendedDebugInfo) {
1429                     debugInfoStack.push(
1430                         "custom writeObject data (class \"" +
1431                         slotDesc.getName() + "\")");
1432                 }
1433                 try {
1434                     curContext = new SerialCallbackContext(obj, slotDesc);
1435                     bout.setBlockDataMode(true);
1436                     slotDesc.invokeWriteObject(obj, this);
1437                     bout.setBlockDataMode(false);
1438                     bout.writeByte(TC_ENDBLOCKDATA);
1439                 } finally {
1440                     curContext.setUsed();
1441                     curContext = oldContext;
1442                     if (extendedDebugInfo) {
< prev index next >