< prev index next >

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

Print this page

  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.security.AccessController;
  30 import java.security.PrivilegedAction;
  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 import sun.reflect.misc.ReflectUtil;
  41 


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

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






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

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


























 164  * @spec serialization/index.html Java Object Serialization Specification
 165  * @author      Mike Warres
 166  * @author      Roger Riggs
 167  * @see java.io.DataOutput
 168  * @see java.io.ObjectInputStream
 169  * @see java.io.Serializable
 170  * @see java.io.Externalizable
 171  * @see <a href="{@docRoot}/../specs/serialization/output.html">
 172  *      <cite>Java Object Serialization Specification,</cite> Section 2, "Object Output Classes"</a>
 173  * @since       1.1
 174  */
 175 public class ObjectOutputStream
 176     extends OutputStream implements ObjectOutput, ObjectStreamConstants
 177 {
 178     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 179 
 180     private static class Caches {
 181         /** cache of subclass security audit results */
 182         static final ClassValue<Boolean> subclassAudits =
 183             new ClassValue<>() {

 328             case PROTOCOL_VERSION_1:
 329             case PROTOCOL_VERSION_2:
 330                 protocol = version;
 331                 break;
 332 
 333             default:
 334                 throw new IllegalArgumentException(
 335                     "unknown version: " + version);
 336         }
 337     }
 338 
 339     /**
 340      * Write the specified object to the ObjectOutputStream.  The class of the
 341      * object, the signature of the class, and the values of the non-transient
 342      * and non-static fields of the class and all of its supertypes are
 343      * written.  Default serialization for a class can be overridden using the
 344      * writeObject and the readObject methods.  Objects referenced by this
 345      * object are written transitively so that a complete equivalent graph of
 346      * objects can be reconstructed by an ObjectInputStream.
 347      *



 348      * <p>Exceptions are thrown for problems with the OutputStream and for
 349      * classes that should not be serialized.  All exceptions are fatal to the
 350      * OutputStream, which is left in an indeterminate state, and it is up to
 351      * the caller to ignore or recover the stream state.
 352      *
 353      * @throws  InvalidClassException Something is wrong with a class used by
 354      *          serialization.
 355      * @throws  NotSerializableException Some object to be serialized does not
 356      *          implement the java.io.Serializable interface.
 357      * @throws  IOException Any exception thrown by the underlying
 358      *          OutputStream.
 359      */
 360     public final void writeObject(Object obj) throws IOException {
 361         if (enableOverride) {
 362             writeObjectOverride(obj);
 363             return;
 364         }
 365         try {
 366             writeObject0(obj, false);
 367         } catch (IOException ex) {

 397      * <ul>
 398      *   <li>An object written via writeUnshared is always serialized in the
 399      *       same manner as a newly appearing object (an object that has not
 400      *       been written to the stream yet), regardless of whether or not the
 401      *       object has been written previously.
 402      *
 403      *   <li>If writeObject is used to write an object that has been previously
 404      *       written with writeUnshared, the previous writeUnshared operation
 405      *       is treated as if it were a write of a separate object.  In other
 406      *       words, ObjectOutputStream will never generate back-references to
 407      *       object data written by calls to writeUnshared.
 408      * </ul>
 409      * While writing an object via writeUnshared does not in itself guarantee a
 410      * unique reference to the object when it is deserialized, it allows a
 411      * single object to be defined multiple times in a stream, so that multiple
 412      * calls to readUnshared by the receiver will not conflict.  Note that the
 413      * rules described above only apply to the base-level object written with
 414      * writeUnshared, and not to any transitively referenced sub-objects in the
 415      * object graph to be serialized.
 416      *



 417      * <p>ObjectOutputStream subclasses which override this method can only be
 418      * constructed in security contexts possessing the
 419      * "enableSubclassImplementation" SerializablePermission; any attempt to
 420      * instantiate such a subclass without this permission will cause a
 421      * SecurityException to be thrown.
 422      *
 423      * @param   obj object to write to stream
 424      * @throws  NotSerializableException if an object in the graph to be
 425      *          serialized does not implement the Serializable interface
 426      * @throws  InvalidClassException if a problem exists with the class of an
 427      *          object to be serialized
 428      * @throws  IOException if an I/O error occurs during serialization
 429      * @since 1.4
 430      */
 431     public void writeUnshared(Object obj) throws IOException {
 432         try {
 433             writeObject0(obj, true);
 434         } catch (IOException ex) {
 435             if (depth == 0) {
 436                 writeFatalException(ex);

1430     private void writeOrdinaryObject(Object obj,
1431                                      ObjectStreamClass desc,
1432                                      boolean unshared)
1433         throws IOException
1434     {
1435         if (extendedDebugInfo) {
1436             debugInfoStack.push(
1437                 (depth == 1 ? "root " : "") + "object (class \"" +
1438                 obj.getClass().getName() + "\", " + obj.toString() + ")");
1439         }
1440         try {
1441             desc.checkSerialize();
1442 
1443             bout.writeByte(TC_OBJECT);
1444             writeClassDesc(desc, false);
1445             handles.assign(unshared ? null : obj);
1446 
1447             if (desc.isRecord()) {
1448                 writeRecordData(obj, desc);
1449             } else if (desc.isExternalizable() && !desc.isProxy()) {



1450                 writeExternalData((Externalizable) obj);
1451             } else {
1452                 writeSerialData(obj, desc);
1453             }
1454         } finally {
1455             if (extendedDebugInfo) {
1456                 debugInfoStack.pop();
1457             }
1458         }
1459     }
1460 
1461     /**
1462      * Writes externalizable data of given object by invoking its
1463      * writeExternal() method.
1464      */
1465     private void writeExternalData(Externalizable obj) throws IOException {
1466         PutFieldImpl oldPut = curPut;
1467         curPut = null;
1468 
1469         if (extendedDebugInfo) {

1478                 bout.setBlockDataMode(true);
1479                 obj.writeExternal(this);
1480                 bout.setBlockDataMode(false);
1481                 bout.writeByte(TC_ENDBLOCKDATA);
1482             }
1483         } finally {
1484             curContext = oldContext;
1485             if (extendedDebugInfo) {
1486                 debugInfoStack.pop();
1487             }
1488         }
1489 
1490         curPut = oldPut;
1491     }
1492 
1493     /** Writes the record component values for the given record object. */
1494     private void writeRecordData(Object obj, ObjectStreamClass desc)
1495         throws IOException
1496     {
1497         assert obj.getClass().isRecord();
1498         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1499         if (slots.length != 1) {
1500             throw new InvalidClassException(
1501                     "expected a single record slot length, but found: " + slots.length);
1502         }
1503 
1504         defaultWriteFields(obj, desc);  // #### seems unnecessary to use the accessors
1505     }
1506 
1507     /**
1508      * Writes instance data for each serializable class of given object, from
1509      * superclass to subclass.
1510      */
1511     private void writeSerialData(Object obj, ObjectStreamClass desc)
1512         throws IOException
1513     {
1514         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1515         for (int i = 0; i < slots.length; i++) {
1516             ObjectStreamClass slotDesc = slots[i].desc;
1517             if (slotDesc.hasWriteObjectMethod()) {
1518                 PutFieldImpl oldPut = curPut;
1519                 curPut = null;
1520                 SerialCallbackContext oldContext = curContext;
1521 
1522                 if (extendedDebugInfo) {
1523                     debugInfoStack.push(
1524                         "custom writeObject data (class \"" +
1525                         slotDesc.getName() + "\")");
1526                 }
1527                 try {
1528                     curContext = new SerialCallbackContext(obj, slotDesc);
1529                     bout.setBlockDataMode(true);
1530                     slotDesc.invokeWriteObject(obj, this);
1531                     bout.setBlockDataMode(false);
1532                     bout.writeByte(TC_ENDBLOCKDATA);
1533                 } finally {
1534                     curContext.setUsed();
1535                     curContext = oldContext;
1536                     if (extendedDebugInfo) {

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

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

 363             case PROTOCOL_VERSION_1:
 364             case PROTOCOL_VERSION_2:
 365                 protocol = version;
 366                 break;
 367 
 368             default:
 369                 throw new IllegalArgumentException(
 370                     "unknown version: " + version);
 371         }
 372     }
 373 
 374     /**
 375      * Write the specified object to the ObjectOutputStream.  The class of the
 376      * object, the signature of the class, and the values of the non-transient
 377      * and non-static fields of the class and all of its supertypes are
 378      * written.  Default serialization for a class can be overridden using the
 379      * writeObject and the readObject methods.  Objects referenced by this
 380      * object are written transitively so that a complete equivalent graph of
 381      * objects can be reconstructed by an ObjectInputStream.
 382      *
 383      * <p>Serialization and deserialization of value classes is described in
 384      * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
 385      *
 386      * <p>Exceptions are thrown for problems with the OutputStream and for
 387      * classes that should not be serialized.  All exceptions are fatal to the
 388      * OutputStream, which is left in an indeterminate state, and it is up to
 389      * the caller to ignore or recover the stream state.
 390      *
 391      * @throws  InvalidClassException Something is wrong with a class used by
 392      *          serialization.
 393      * @throws  NotSerializableException Some object to be serialized does not
 394      *          implement the java.io.Serializable interface.
 395      * @throws  IOException Any exception thrown by the underlying
 396      *          OutputStream.
 397      */
 398     public final void writeObject(Object obj) throws IOException {
 399         if (enableOverride) {
 400             writeObjectOverride(obj);
 401             return;
 402         }
 403         try {
 404             writeObject0(obj, false);
 405         } catch (IOException ex) {

 435      * <ul>
 436      *   <li>An object written via writeUnshared is always serialized in the
 437      *       same manner as a newly appearing object (an object that has not
 438      *       been written to the stream yet), regardless of whether or not the
 439      *       object has been written previously.
 440      *
 441      *   <li>If writeObject is used to write an object that has been previously
 442      *       written with writeUnshared, the previous writeUnshared operation
 443      *       is treated as if it were a write of a separate object.  In other
 444      *       words, ObjectOutputStream will never generate back-references to
 445      *       object data written by calls to writeUnshared.
 446      * </ul>
 447      * While writing an object via writeUnshared does not in itself guarantee a
 448      * unique reference to the object when it is deserialized, it allows a
 449      * single object to be defined multiple times in a stream, so that multiple
 450      * calls to readUnshared by the receiver will not conflict.  Note that the
 451      * rules described above only apply to the base-level object written with
 452      * writeUnshared, and not to any transitively referenced sub-objects in the
 453      * object graph to be serialized.
 454      *
 455      * <p>Serialization and deserialization of value classes is described in
 456      * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
 457      *
 458      * <p>ObjectOutputStream subclasses which override this method can only be
 459      * constructed in security contexts possessing the
 460      * "enableSubclassImplementation" SerializablePermission; any attempt to
 461      * instantiate such a subclass without this permission will cause a
 462      * SecurityException to be thrown.
 463      *
 464      * @param   obj object to write to stream
 465      * @throws  NotSerializableException if an object in the graph to be
 466      *          serialized does not implement the Serializable interface
 467      * @throws  InvalidClassException if a problem exists with the class of an
 468      *          object to be serialized
 469      * @throws  IOException if an I/O error occurs during serialization
 470      * @since 1.4
 471      */
 472     public void writeUnshared(Object obj) throws IOException {
 473         try {
 474             writeObject0(obj, true);
 475         } catch (IOException ex) {
 476             if (depth == 0) {
 477                 writeFatalException(ex);

1471     private void writeOrdinaryObject(Object obj,
1472                                      ObjectStreamClass desc,
1473                                      boolean unshared)
1474         throws IOException
1475     {
1476         if (extendedDebugInfo) {
1477             debugInfoStack.push(
1478                 (depth == 1 ? "root " : "") + "object (class \"" +
1479                 obj.getClass().getName() + "\", " + obj.toString() + ")");
1480         }
1481         try {
1482             desc.checkSerialize();
1483 
1484             bout.writeByte(TC_OBJECT);
1485             writeClassDesc(desc, false);
1486             handles.assign(unshared ? null : obj);
1487 
1488             if (desc.isRecord()) {
1489                 writeRecordData(obj, desc);
1490             } else if (desc.isExternalizable() && !desc.isProxy()) {
1491                 if (desc.isValue())
1492                     throw new InvalidClassException("Externalizable not valid for value class "
1493                             + desc.forClass().getName());
1494                 writeExternalData((Externalizable) obj);
1495             } else {
1496                 writeSerialData(obj, desc);
1497             }
1498         } finally {
1499             if (extendedDebugInfo) {
1500                 debugInfoStack.pop();
1501             }
1502         }
1503     }
1504 
1505     /**
1506      * Writes externalizable data of given object by invoking its
1507      * writeExternal() method.
1508      */
1509     private void writeExternalData(Externalizable obj) throws IOException {
1510         PutFieldImpl oldPut = curPut;
1511         curPut = null;
1512 
1513         if (extendedDebugInfo) {

1522                 bout.setBlockDataMode(true);
1523                 obj.writeExternal(this);
1524                 bout.setBlockDataMode(false);
1525                 bout.writeByte(TC_ENDBLOCKDATA);
1526             }
1527         } finally {
1528             curContext = oldContext;
1529             if (extendedDebugInfo) {
1530                 debugInfoStack.pop();
1531             }
1532         }
1533 
1534         curPut = oldPut;
1535     }
1536 
1537     /** Writes the record component values for the given record object. */
1538     private void writeRecordData(Object obj, ObjectStreamClass desc)
1539         throws IOException
1540     {
1541         assert obj.getClass().isRecord();
1542         List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
1543         if (slots.size() != 1) {
1544             throw new InvalidClassException(
1545                     "expected a single record slot length, but found: " + slots.size());
1546         }
1547 
1548         defaultWriteFields(obj, desc);  // #### seems unnecessary to use the accessors
1549     }
1550 
1551     /**
1552      * Writes instance data for each serializable class of given object, from
1553      * superclass to subclass.
1554      */
1555     private void writeSerialData(Object obj, ObjectStreamClass desc)
1556         throws IOException
1557     {
1558        List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
1559         for (int i = 0; i < slots.size(); i++) {
1560             ObjectStreamClass slotDesc = slots.get(i).desc;
1561             if (slotDesc.hasWriteObjectMethod()) {
1562                 PutFieldImpl oldPut = curPut;
1563                 curPut = null;
1564                 SerialCallbackContext oldContext = curContext;
1565 
1566                 if (extendedDebugInfo) {
1567                     debugInfoStack.push(
1568                         "custom writeObject data (class \"" +
1569                         slotDesc.getName() + "\")");
1570                 }
1571                 try {
1572                     curContext = new SerialCallbackContext(obj, slotDesc);
1573                     bout.setBlockDataMode(true);
1574                     slotDesc.invokeWriteObject(obj, this);
1575                     bout.setBlockDataMode(false);
1576                     bout.writeByte(TC_ENDBLOCKDATA);
1577                 } finally {
1578                     curContext.setUsed();
1579                     curContext = oldContext;
1580                     if (extendedDebugInfo) {
< prev index next >