< prev index next >

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

Print this page

   1 /*
   2  * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.  Oracle designates this
   9  * particular file as subject to the "Classpath" exception as provided
  10  * by Oracle in the LICENSE file that accompanied this code.
  11  *
  12  * This code is distributed in the hope that it will be useful, but WITHOUT
  13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15  * version 2 for more details (a copy is included in the LICENSE file that
  16  * accompanied this code).
  17  *
  18  * You should have received a copy of the GNU General Public License version
  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

 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) {

   1 /*
   2  * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.  Oracle designates this
   9  * particular file as subject to the "Classpath" exception as provided
  10  * by Oracle in the LICENSE file that accompanied this code.
  11  *
  12  * This code is distributed in the hope that it will be useful, but WITHOUT
  13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15  * version 2 for more details (a copy is included in the LICENSE file that
  16  * accompanied this code).
  17  *
  18  * You should have received a copy of the GNU General Public License version
  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

 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 >