< prev index next >

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

Print this page

  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.lang.runtime.ExactConversionsSupport;
  30 
  31 import java.util.ArrayList;
  32 import java.util.Arrays;
  33 import java.util.List;
  34 import java.util.Objects;
  35 import java.util.StringJoiner;
  36 
  37 import jdk.internal.util.ByteArray;
  38 import jdk.internal.access.JavaLangAccess;
  39 import jdk.internal.access.SharedSecrets;
  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  *
 136  * <p>Enum constants are serialized differently than ordinary serializable or
 137  * externalizable objects.  The serialized form of an enum constant consists
 138  * solely of its name; field values of the constant are not transmitted.  To
 139  * serialize an enum constant, ObjectOutputStream writes the string returned by
 140  * the constant's name method.  Like other serializable or externalizable
 141  * objects, enum constants can function as the targets of back references
 142  * appearing subsequently in the serialization stream.  The process by which
 143  * enum constants are serialized cannot be customized; any class-specific
 144  * writeObject and writeReplace methods defined by enum types are ignored
 145  * during serialization.  Similarly, any serialPersistentFields or
 146  * serialVersionUID field declarations are also ignored--all enum types have a
 147  * fixed serialVersionUID of 0L.
 148  *
 149  * <p>Primitive data, excluding serializable fields and externalizable data, is
 150  * written to the ObjectOutputStream in block-data records. A block data record
 151  * is composed of a header and data. The block data header consists of a marker
 152  * and the number of bytes to follow the header.  Consecutive primitive data
 153  * writes are merged into one block-data record.  The blocking factor used for
 154  * a block-data record will be 1024 bytes.  Each block-data record will be
 155  * filled up to 1024 bytes, or be written whenever there is a termination of
 156  * block-data mode.  Calls to the ObjectOutputStream methods writeObject,
 157  * defaultWriteObject and writeFields initially terminate any existing
 158  * block-data record.
 159  *

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


























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

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



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

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



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

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

  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.lang.runtime.ExactConversionsSupport;
  30 
  31 import java.util.ArrayList;
  32 import java.util.Arrays;
  33 import java.util.List;
  34 import java.util.Objects;
  35 import java.util.StringJoiner;
  36 
  37 import jdk.internal.util.ByteArray;
  38 import jdk.internal.access.JavaLangAccess;
  39 import jdk.internal.access.SharedSecrets;
  40 
  41 import static java.io.ObjectInputStream.TRACE;
  42 
  43 import static jdk.internal.util.ModifiedUtf.putChar;
  44 import static jdk.internal.util.ModifiedUtf.utfLen;
  45 
  46 /**
  47  * An ObjectOutputStream writes primitive data types and graphs of Java objects
  48  * to an OutputStream.  The objects can be read (reconstituted) using an
  49  * ObjectInputStream.  Persistent storage of objects can be accomplished by
  50  * using a file for the stream.  If the stream is a network socket stream, the
  51  * objects can be reconstituted on another host or in another process.
  52  *
  53  * <p>Only objects that support the java.io.Serializable interface can be
  54  * written to streams.  The class of each serializable object is encoded
  55  * including the class name and signature of the class, the values of the
  56  * object's fields and arrays, and the closure of any other objects referenced
  57  * from the initial objects.
  58  *
  59  * <p>The method writeObject is used to write an object to the stream.  Any
  60  * object, including Strings and arrays, is written with writeObject. Multiple
  61  * objects or primitives can be written to the stream.  The objects must be
  62  * read back from the corresponding ObjectInputstream with the same types and

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

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

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

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