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