< prev index next > src/java.base/share/classes/java/io/ObjectOutputStream.java
Print this page
import jdk.internal.util.ByteArray;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import sun.reflect.misc.ReflectUtil;
+ import static java.io.ObjectInputStream.TRACE;
+
import static jdk.internal.util.ModifiedUtf.putChar;
import static jdk.internal.util.ModifiedUtf.utfLen;
/**
* An ObjectOutputStream writes primitive data types and graphs of Java objects
* form. The methods of the Externalizable interface, writeExternal and
* readExternal, are called to save and restore the objects state. When
* implemented by a class they can write and read their own state using all of
* the methods of ObjectOutput and ObjectInput. It is the responsibility of
* the objects to handle any versioning that occurs.
+ * Value classes implementing {@link Externalizable} cannot be serialized
+ * or deserialized, the value object is immutable and the state cannot be restored.
+ * Use {@link Serializable} {@code writeReplace} to delegate to another serializable
+ * object such as a record.
+ *
+ * Value objects cannot be {@code java.io.Externalizable}.
*
* <p>Enum constants are serialized differently than ordinary serializable or
* externalizable objects. The serialized form of an enum constant consists
* solely of its name; field values of the constant are not transmitted. To
* serialize an enum constant, ObjectOutputStream writes the string returned by
* filled up to 1024 bytes, or be written whenever there is a termination of
* block-data mode. Calls to the ObjectOutputStream methods writeObject,
* defaultWriteObject and writeFields initially terminate any existing
* block-data record.
*
+ * <a id="record-serialization"></a>
* <p>Records are serialized differently than ordinary serializable or externalizable
* objects, see <a href="ObjectInputStream.html#record-serialization">record serialization</a>.
*
+ * <a id="valueclass-serialization"></a>
+ * <p>Value classes are {@linkplain Serializable} through the use of the serialization proxy pattern.
+ * The serialization protocol does not support a standard serialized form for value classes.
+ * The value class delegates to a serialization proxy by supplying an alternate
+ * record or object to be serialized instead of the value class.
+ * When the proxy is deserialized it re-constructs the value object and returns the value object.
+ * For example,
+ * {@snippet lang="java" :
+ * value class ZipCode implements Serializable { // @highlight substring="value class"
+ * private static final long serialVersionUID = 1L;
+ * private int zipCode;
+ * public ZipCode(int zip) { this.zipCode = zip; }
+ * public int zipCode() { return zipCode; }
+ *
+ * public Object writeReplace() { // @highlight substring="writeReplace"
+ * return new ZipCodeProxy(zipCode);
+ * }
+ *
+ * private record ZipCodeProxy(int zipCode) implements Serializable {
+ * public Object readResolve() { // @highlight substring="readResolve"
+ * return new ZipCode(zipCode);
+ * }
+ * }
+ * }
+ * }
+ *
* @spec serialization/index.html Java Object Serialization Specification
* @author Mike Warres
* @author Roger Riggs
* @see java.io.DataOutput
* @see java.io.ObjectInputStream
* written. Default serialization for a class can be overridden using the
* writeObject and the readObject methods. Objects referenced by this
* object are written transitively so that a complete equivalent graph of
* objects can be reconstructed by an ObjectInputStream.
*
+ * <p>Serialization and deserialization of value classes is described in
+ * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
+ *
* <p>Exceptions are thrown for problems with the OutputStream and for
* classes that should not be serialized. All exceptions are fatal to the
* OutputStream, which is left in an indeterminate state, and it is up to
* the caller to ignore or recover the stream state.
*
* calls to readUnshared by the receiver will not conflict. Note that the
* rules described above only apply to the base-level object written with
* writeUnshared, and not to any transitively referenced sub-objects in the
* object graph to be serialized.
*
+ * <p>Serialization and deserialization of value classes is described in
+ * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
+ *
* <p>ObjectOutputStream subclasses which override this method can only be
* constructed in security contexts possessing the
* "enableSubclassImplementation" SerializablePermission; any attempt to
* instantiate such a subclass without this permission will cause a
* SecurityException to be thrown.
handles.assign(unshared ? null : obj);
if (desc.isRecord()) {
writeRecordData(obj, desc);
} else if (desc.isExternalizable() && !desc.isProxy()) {
+ if (desc.isValue())
+ throw new InvalidClassException("Externalizable not valid for value class "
+ + desc.forClass().getName());
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);
}
} finally {
/** Writes the record component values for the given record object. */
private void writeRecordData(Object obj, ObjectStreamClass desc)
throws IOException
{
assert obj.getClass().isRecord();
! ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
! if (slots.length != 1) {
throw new InvalidClassException(
! "expected a single record slot length, but found: " + slots.length);
}
defaultWriteFields(obj, desc); // #### seems unnecessary to use the accessors
}
/** Writes the record component values for the given record object. */
private void writeRecordData(Object obj, ObjectStreamClass desc)
throws IOException
{
assert obj.getClass().isRecord();
! List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
! if (slots.size() != 1) {
throw new InvalidClassException(
! "expected a single record slot length, but found: " + slots.size());
}
defaultWriteFields(obj, desc); // #### seems unnecessary to use the accessors
}
* superclass to subclass.
*/
private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
! ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
! for (int i = 0; i < slots.length; i++) {
! ObjectStreamClass slotDesc = slots[i].desc;
if (slotDesc.hasWriteObjectMethod()) {
PutFieldImpl oldPut = curPut;
curPut = null;
SerialCallbackContext oldContext = curContext;
* superclass to subclass.
*/
private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
! List<ObjectStreamClass.ClassDataSlot> slots = desc.getClassDataLayout();
! for (int i = 0; i < slots.size(); i++) {
! ObjectStreamClass slotDesc = slots.get(i).desc;
if (slotDesc.hasWriteObjectMethod()) {
PutFieldImpl oldPut = curPut;
curPut = null;
SerialCallbackContext oldContext = curContext;
< prev index next >