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