< 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     private static class Caches {
 178         /** cache of subclass security audit results */
 179         static final ClassValue<Boolean> subclassAudits =
 180             new ClassValue<>() {

 298             case PROTOCOL_VERSION_1:
 299             case PROTOCOL_VERSION_2:
 300                 protocol = version;
 301                 break;
 302 
 303             default:
 304                 throw new IllegalArgumentException(
 305                     "unknown version: " + version);
 306         }
 307     }
 308 
 309     /**
 310      * Write the specified object to the ObjectOutputStream.  The class of the
 311      * object, the signature of the class, and the values of the non-transient
 312      * and non-static fields of the class and all of its supertypes are
 313      * written.  Default serialization for a class can be overridden using the
 314      * writeObject and the readObject methods.  Objects referenced by this
 315      * object are written transitively so that a complete equivalent graph of
 316      * objects can be reconstructed by an ObjectInputStream.
 317      *



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

1331     private void writeOrdinaryObject(Object obj,
1332                                      ObjectStreamClass desc,
1333                                      boolean unshared)
1334         throws IOException
1335     {
1336         if (extendedDebugInfo) {
1337             debugInfoStack.push(
1338                 (depth == 1 ? "root " : "") + "object (class \"" +
1339                 obj.getClass().getName() + "\", " + obj.toString() + ")");
1340         }
1341         try {
1342             desc.checkSerialize();
1343 
1344             bout.writeByte(TC_OBJECT);
1345             writeClassDesc(desc, false);
1346             handles.assign(unshared ? null : obj);
1347 
1348             if (desc.isRecord()) {
1349                 writeRecordData(obj, desc);
1350             } else if (desc.isExternalizable() && !desc.isProxy()) {



1351                 writeExternalData((Externalizable) obj);
1352             } else {
1353                 writeSerialData(obj, desc);
1354             }
1355         } finally {
1356             if (extendedDebugInfo) {
1357                 debugInfoStack.pop();
1358             }
1359         }
1360     }
1361 
1362     /**
1363      * Writes externalizable data of given object by invoking its
1364      * writeExternal() method.
1365      */
1366     private void writeExternalData(Externalizable obj) throws IOException {
1367         PutFieldImpl oldPut = curPut;
1368         curPut = null;
1369 
1370         if (extendedDebugInfo) {

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

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

1369     private void writeOrdinaryObject(Object obj,
1370                                      ObjectStreamClass desc,
1371                                      boolean unshared)
1372         throws IOException
1373     {
1374         if (extendedDebugInfo) {
1375             debugInfoStack.push(
1376                 (depth == 1 ? "root " : "") + "object (class \"" +
1377                 obj.getClass().getName() + "\", " + obj.toString() + ")");
1378         }
1379         try {
1380             desc.checkSerialize();
1381 
1382             bout.writeByte(TC_OBJECT);
1383             writeClassDesc(desc, false);
1384             handles.assign(unshared ? null : obj);
1385 
1386             if (desc.isRecord()) {
1387                 writeRecordData(obj, desc);
1388             } else if (desc.isExternalizable() && !desc.isProxy()) {
1389                 if (desc.isValue())
1390                     throw new InvalidClassException("Externalizable not valid for value class "
1391                             + desc.forClass().getName());
1392                 writeExternalData((Externalizable) obj);
1393             } else {
1394                 writeSerialData(obj, desc);
1395             }
1396         } finally {
1397             if (extendedDebugInfo) {
1398                 debugInfoStack.pop();
1399             }
1400         }
1401     }
1402 
1403     /**
1404      * Writes externalizable data of given object by invoking its
1405      * writeExternal() method.
1406      */
1407     private void writeExternalData(Externalizable obj) throws IOException {
1408         PutFieldImpl oldPut = curPut;
1409         curPut = null;
1410 
1411         if (extendedDebugInfo) {

1420                 bout.setBlockDataMode(true);
1421                 obj.writeExternal(this);
1422                 bout.setBlockDataMode(false);
1423                 bout.writeByte(TC_ENDBLOCKDATA);
1424             }
1425         } finally {
1426             curContext = oldContext;
1427             if (extendedDebugInfo) {
1428                 debugInfoStack.pop();
1429             }
1430         }
1431 
1432         curPut = oldPut;
1433     }
1434 
1435     /** Writes the record component values for the given record object. */
1436     private void writeRecordData(Object obj, ObjectStreamClass desc)
1437         throws IOException
1438     {
1439         assert obj.getClass().isRecord();
1440         List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
1441         if (slots.size() != 1) {
1442             throw new InvalidClassException(
1443                     "expected a single record slot length, but found: " + slots.size());
1444         }
1445 
1446         defaultWriteFields(obj, desc);  // #### seems unnecessary to use the accessors
1447     }
1448 
1449     /**
1450      * Writes instance data for each serializable class of given object, from
1451      * superclass to subclass.
1452      */
1453     private void writeSerialData(Object obj, ObjectStreamClass desc)
1454         throws IOException
1455     {
1456        List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
1457         for (int i = 0; i < slots.size(); i++) {
1458             ObjectStreamClass slotDesc = slots.get(i).desc;
1459             if (slotDesc.hasWriteObjectMethod()) {
1460                 PutFieldImpl oldPut = curPut;
1461                 curPut = null;
1462                 SerialCallbackContext oldContext = curContext;
1463 
1464                 if (extendedDebugInfo) {
1465                     debugInfoStack.push(
1466                         "custom writeObject data (class \"" +
1467                         slotDesc.getName() + "\")");
1468                 }
1469                 try {
1470                     curContext = new SerialCallbackContext(obj, slotDesc);
1471                     bout.setBlockDataMode(true);
1472                     slotDesc.invokeWriteObject(obj, this);
1473                     bout.setBlockDataMode(false);
1474                     bout.writeByte(TC_ENDBLOCKDATA);
1475                 } finally {
1476                     curContext.setUsed();
1477                     curContext = oldContext;
1478                     if (extendedDebugInfo) {
< prev index next >