< prev index next > src/java.base/share/classes/java/io/ObjectInputStream.java
Print this page
/*
! * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
/*
! * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*/
package java.io;
import java.io.ObjectInputFilter.Config;
! import java.io.ObjectStreamClass.RecordSupport;
import java.lang.System.Logger;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Modifier;
*/
package java.io;
import java.io.ObjectInputFilter.Config;
! import java.io.ObjectStreamClass.AlternativeDeserialization;
import java.lang.System.Logger;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Modifier;
* as readObject and writeObject, are ignored for serializable records. See
* <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
* <cite>Java Object Serialization Specification,</cite> Section 1.13,
* "Serialization of Records"</a> for additional information.
*
+ * <div class="preview-block">
+ * <div class="preview-comment">
+ * <p>{@linkplain Class#isValue Value classes} that are not records cannot be
+ * deserialized directly. To serialize an instance of a value class, a proxy
+ * object should be used instead. That object can then implement
+ * <a href="{@docRoot}/../specs/serialization/input.html#the-readresolve-method">
+ * {@code readResolve}</a> to construct and return the expected value class
+ * instance.
+ * </div>
+ * </div>
+ *
* @spec serialization/index.html Java Object Serialization Specification
* @author Mike Warres
* @author Roger Riggs
* @see java.io.DataInput
* @see java.io.ObjectOutputStream
* <p>Exceptions are thrown for problems with the InputStream and for
* classes that should not be deserialized. All exceptions are fatal to
* the InputStream and leave it in an indeterminate state; it is up to the
* caller to ignore or recover the stream state.
*
+ * <div class="preview-block">
+ * <div class="preview-comment">
+ * <p>An object in the stream that instantiates a concrete
+ * {@linkplain Class#isValue value class}, or that extends a
+ * Serializable abstract value class that declares instance fields,
+ * can only be deserialized if it is a record or a boxed primitive
+ * value. Otherwise, {@code readObject} throws an
+ * {@code InvalidClassException}.
+ * </div>
+ * </div>
+ *
* @throws ClassNotFoundException Class of a serialized object cannot be
* found.
* @throws InvalidClassException Something is wrong with a class used by
* deserialization.
* @throws StreamCorruptedException Control information in the
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
final boolean isRecord = desc.isRecord();
! if (isRecord) {
assert obj == null;
! obj = readRecord(desc);
if (!unshared)
handles.setObject(passHandle, obj);
} else if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
final boolean isRecord = desc.isRecord();
! if (isRecord || desc.hasDeserializer()) {
assert obj == null;
! obj = readAlternative(desc);
if (!unshared)
handles.setObject(passHandle, obj);
} else if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
* most likely throw a StreamCorruptedException.
*/
}
/**
! * Reads and returns a record.
* If an exception is marked for any of the fields, the dependency
! * mechanism marks the record as having an exception.
! * Null is returned from readRecord and later the exception is thrown at
* the exit of {@link #readObject(Class)}.
*/
! private Object readRecord(ObjectStreamClass desc) throws IOException {
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
if (slots.length != 1) {
// skip any superclass stream field values
for (int i = 0; i < slots.length-1; i++) {
if (slots[i].hasData) {
* most likely throw a StreamCorruptedException.
*/
}
/**
! * Reads and returns an alternatively-deserialized object, such as a record
+ * or a wrapper class as a value class.
* If an exception is marked for any of the fields, the dependency
! * mechanism marks the object as having an exception.
! * Null is returned from readFromFactory and later the exception is thrown at
* the exit of {@link #readObject(Class)}.
*/
! private Object readAlternative(ObjectStreamClass desc) throws IOException {
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
if (slots.length != 1) {
// skip any superclass stream field values
for (int i = 0; i < slots.length-1; i++) {
if (slots[i].hasData) {
}
}
FieldValues fieldValues = new FieldValues(desc, true);
if (handles.lookupException(passHandle) != null) {
! return null; // slot marked with exception, don't create record
}
! // get canonical record constructor adapted to take two arguments:
// - byte[] primValues
// - Object[] objValues
// and return Object
! MethodHandle ctrMH = RecordSupport.deserializationCtr(desc);
try {
! return (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
} catch (Exception e) {
throw new InvalidObjectException(e.getMessage(), e);
} catch (Error e) {
throw e;
} catch (Throwable t) {
}
}
FieldValues fieldValues = new FieldValues(desc, true);
if (handles.lookupException(passHandle) != null) {
! return null; // slot marked with exception, don't create object
}
! // get the factory adapted to take two arguments:
// - byte[] primValues
// - Object[] objValues
// and return Object
! MethodHandle factoryMH = AlternativeDeserialization.getFactory(desc);
try {
! return (Object) factoryMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
} catch (Exception e) {
throw new InvalidObjectException(e.getMessage(), e);
} catch (Error e) {
throw e;
} catch (Throwable t) {
< prev index next >