1 /*
2 * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.io;
27
28 import java.io.ObjectInputFilter.Config;
29 import java.io.ObjectStreamClass.RecordSupport;
30 import java.lang.System.Logger;
31 import java.lang.invoke.MethodHandle;
32 import java.lang.reflect.Array;
33 import java.lang.reflect.InvocationHandler;
34 import java.lang.reflect.Modifier;
35 import java.lang.reflect.Proxy;
36 import java.nio.charset.StandardCharsets;
37 import java.util.Arrays;
38 import java.util.Objects;
39
40 import jdk.internal.access.JavaLangAccess;
41 import jdk.internal.access.SharedSecrets;
42 import jdk.internal.event.DeserializationEvent;
43 import jdk.internal.misc.Unsafe;
44 import jdk.internal.util.ByteArray;
45
46 /**
47 * An ObjectInputStream deserializes primitive data and objects previously
48 * written using an ObjectOutputStream.
49 *
218 * the stream; the deserialized constant is then obtained by calling the static
219 * method {@code Enum.valueOf(Class, String)} with the enum constant's
220 * base type and the received constant name as arguments. Like other
221 * serializable or externalizable objects, enum constants can function as the
222 * targets of back references appearing subsequently in the serialization
223 * stream. The process by which enum constants are deserialized cannot be
224 * customized: any class-specific readObject, readObjectNoData, and readResolve
225 * methods defined by enum types are ignored during deserialization.
226 * Similarly, any serialPersistentFields or serialVersionUID field declarations
227 * are also ignored--all enum types have a fixed serialVersionUID of 0L.
228 *
229 * <a id="record-serialization"></a>
230 * <p>Records are serialized differently than ordinary serializable or externalizable
231 * objects. During deserialization the record's canonical constructor is invoked
232 * to construct the record object. Certain serialization-related methods, such
233 * as readObject and writeObject, are ignored for serializable records. See
234 * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
235 * <cite>Java Object Serialization Specification,</cite> Section 1.13,
236 * "Serialization of Records"</a> for additional information.
237 *
238 * @spec serialization/index.html Java Object Serialization Specification
239 * @author Mike Warres
240 * @author Roger Riggs
241 * @see java.io.DataInput
242 * @see java.io.ObjectOutputStream
243 * @see java.io.Serializable
244 * @see <a href="{@docRoot}/../specs/serialization/input.html">
245 * <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
246 * @since 1.1
247 */
248 public class ObjectInputStream
249 extends InputStream implements ObjectInput, ObjectStreamConstants
250 {
251 /** handle value representing null */
252 private static final int NULL_HANDLE = -1;
253
254 /** marker for unshared objects in internal handle table */
255 private static final Object unsharedMarker = new Object();
256
257 private static class Caches {
413 * Default deserializing for a class can be overridden using the writeObject
414 * and readObject methods. Objects referenced by this object are read
415 * transitively so that a complete equivalent graph of objects is
416 * reconstructed by readObject.
417 *
418 * <p>The root object is completely restored when all of its fields and the
419 * objects it references are completely restored. At this point the object
420 * validation callbacks are executed in order based on their registered
421 * priorities. The callbacks are registered by objects (in the readObject
422 * special methods) as they are individually restored.
423 *
424 * <p>The deserialization filter, when not {@code null}, is invoked for
425 * each object (regular or class) read to reconstruct the root object.
426 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
427 *
428 * <p>Exceptions are thrown for problems with the InputStream and for
429 * classes that should not be deserialized. All exceptions are fatal to
430 * the InputStream and leave it in an indeterminate state; it is up to the
431 * caller to ignore or recover the stream state.
432 *
433 * @throws ClassNotFoundException Class of a serialized object cannot be
434 * found.
435 * @throws InvalidClassException Something is wrong with a class used by
436 * deserialization.
437 * @throws StreamCorruptedException Control information in the
438 * stream is inconsistent.
439 * @throws OptionalDataException Primitive data was found in the
440 * stream instead of objects.
441 * @throws IOException Any of the usual Input/Output related exceptions.
442 */
443 public final Object readObject()
444 throws IOException, ClassNotFoundException {
445 return readObject(Object.class);
446 }
447
448 /**
449 * Reads a String and only a string.
450 *
451 * @return the String read
452 * @throws EOFException If end of file is reached.
2105 if (cl == String.class || cl == Class.class
2106 || cl == ObjectStreamClass.class) {
2107 throw new InvalidClassException("invalid class descriptor");
2108 }
2109
2110 Object obj;
2111 try {
2112 obj = desc.isInstantiable() ? desc.newInstance() : null;
2113 } catch (Exception ex) {
2114 throw new InvalidClassException(desc.forClass().getName(),
2115 "unable to create instance", ex);
2116 }
2117
2118 passHandle = handles.assign(unshared ? unsharedMarker : obj);
2119 ClassNotFoundException resolveEx = desc.getResolveException();
2120 if (resolveEx != null) {
2121 handles.markException(passHandle, resolveEx);
2122 }
2123
2124 final boolean isRecord = desc.isRecord();
2125 if (isRecord) {
2126 assert obj == null;
2127 obj = readRecord(desc);
2128 if (!unshared)
2129 handles.setObject(passHandle, obj);
2130 } else if (desc.isExternalizable()) {
2131 readExternalData((Externalizable) obj, desc);
2132 } else {
2133 readSerialData(obj, desc);
2134 }
2135
2136 handles.finish(passHandle);
2137
2138 if (obj != null &&
2139 handles.lookupException(passHandle) == null &&
2140 desc.hasReadResolveMethod())
2141 {
2142 Object rep = desc.invokeReadResolve(obj);
2143 if (unshared && rep.getClass().isArray()) {
2144 rep = cloneArray(rep);
2145 }
2146 if (rep != obj) {
2147 // Filter the replacement object
2197 } finally {
2198 if (oldContext != null)
2199 oldContext.check();
2200 curContext = oldContext;
2201 }
2202 /*
2203 * At this point, if the externalizable data was not written in
2204 * block-data form and either the externalizable class doesn't exist
2205 * locally (i.e., obj == null) or readExternal() just threw a
2206 * CNFException, then the stream is probably in an inconsistent state,
2207 * since some (or all) of the externalizable data may not have been
2208 * consumed. Since there's no "correct" action to take in this case,
2209 * we mimic the behavior of past serialization implementations and
2210 * blindly hope that the stream is in sync; if it isn't and additional
2211 * externalizable data remains in the stream, a subsequent read will
2212 * most likely throw a StreamCorruptedException.
2213 */
2214 }
2215
2216 /**
2217 * Reads and returns a record.
2218 * If an exception is marked for any of the fields, the dependency
2219 * mechanism marks the record as having an exception.
2220 * Null is returned from readRecord and later the exception is thrown at
2221 * the exit of {@link #readObject(Class)}.
2222 */
2223 private Object readRecord(ObjectStreamClass desc) throws IOException {
2224 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2225 if (slots.length != 1) {
2226 // skip any superclass stream field values
2227 for (int i = 0; i < slots.length-1; i++) {
2228 if (slots[i].hasData) {
2229 new FieldValues(slots[i].desc, true);
2230 }
2231 }
2232 }
2233
2234 FieldValues fieldValues = new FieldValues(desc, true);
2235 if (handles.lookupException(passHandle) != null) {
2236 return null; // slot marked with exception, don't create record
2237 }
2238
2239 // get canonical record constructor adapted to take two arguments:
2240 // - byte[] primValues
2241 // - Object[] objValues
2242 // and return Object
2243 MethodHandle ctrMH = RecordSupport.deserializationCtr(desc);
2244
2245 try {
2246 return (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2247 } catch (Exception e) {
2248 throw new InvalidObjectException(e.getMessage(), e);
2249 } catch (Error e) {
2250 throw e;
2251 } catch (Throwable t) {
2252 throw new InvalidObjectException("ReflectiveOperationException " +
2253 "during deserialization", t);
2254 }
2255 }
2256
2257 /**
2258 * Reads (or attempts to skip, if obj is null or is tagged with a
2259 * ClassNotFoundException) instance data for each serializable class of
2260 * object in stream, from superclass to subclass. Expects that passHandle
2261 * is set to obj's handle before this method is called.
2262 */
2263 private void readSerialData(Object obj, ObjectStreamClass desc)
2264 throws IOException
2265 {
2266 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
|
1 /*
2 * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.io;
27
28 import java.io.ObjectInputFilter.Config;
29 import java.io.ObjectStreamClass.AlternativeDeserialization;
30 import java.lang.System.Logger;
31 import java.lang.invoke.MethodHandle;
32 import java.lang.reflect.Array;
33 import java.lang.reflect.InvocationHandler;
34 import java.lang.reflect.Modifier;
35 import java.lang.reflect.Proxy;
36 import java.nio.charset.StandardCharsets;
37 import java.util.Arrays;
38 import java.util.Objects;
39
40 import jdk.internal.access.JavaLangAccess;
41 import jdk.internal.access.SharedSecrets;
42 import jdk.internal.event.DeserializationEvent;
43 import jdk.internal.misc.Unsafe;
44 import jdk.internal.util.ByteArray;
45
46 /**
47 * An ObjectInputStream deserializes primitive data and objects previously
48 * written using an ObjectOutputStream.
49 *
218 * the stream; the deserialized constant is then obtained by calling the static
219 * method {@code Enum.valueOf(Class, String)} with the enum constant's
220 * base type and the received constant name as arguments. Like other
221 * serializable or externalizable objects, enum constants can function as the
222 * targets of back references appearing subsequently in the serialization
223 * stream. The process by which enum constants are deserialized cannot be
224 * customized: any class-specific readObject, readObjectNoData, and readResolve
225 * methods defined by enum types are ignored during deserialization.
226 * Similarly, any serialPersistentFields or serialVersionUID field declarations
227 * are also ignored--all enum types have a fixed serialVersionUID of 0L.
228 *
229 * <a id="record-serialization"></a>
230 * <p>Records are serialized differently than ordinary serializable or externalizable
231 * objects. During deserialization the record's canonical constructor is invoked
232 * to construct the record object. Certain serialization-related methods, such
233 * as readObject and writeObject, are ignored for serializable records. See
234 * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
235 * <cite>Java Object Serialization Specification,</cite> Section 1.13,
236 * "Serialization of Records"</a> for additional information.
237 *
238 * <div class="preview-block">
239 * <div class="preview-comment">
240 * <p>{@linkplain Class#isValue Value classes} that are not records cannot be
241 * deserialized directly. To serialize an instance of a value class, a proxy
242 * object should be used instead. That object can then implement
243 * <a href="{@docRoot}/../specs/serialization/input.html#the-readresolve-method">
244 * {@code readResolve}</a> to construct and return the expected value class
245 * instance.
246 * </div>
247 * </div>
248 *
249 * @spec serialization/index.html Java Object Serialization Specification
250 * @author Mike Warres
251 * @author Roger Riggs
252 * @see java.io.DataInput
253 * @see java.io.ObjectOutputStream
254 * @see java.io.Serializable
255 * @see <a href="{@docRoot}/../specs/serialization/input.html">
256 * <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
257 * @since 1.1
258 */
259 public class ObjectInputStream
260 extends InputStream implements ObjectInput, ObjectStreamConstants
261 {
262 /** handle value representing null */
263 private static final int NULL_HANDLE = -1;
264
265 /** marker for unshared objects in internal handle table */
266 private static final Object unsharedMarker = new Object();
267
268 private static class Caches {
424 * Default deserializing for a class can be overridden using the writeObject
425 * and readObject methods. Objects referenced by this object are read
426 * transitively so that a complete equivalent graph of objects is
427 * reconstructed by readObject.
428 *
429 * <p>The root object is completely restored when all of its fields and the
430 * objects it references are completely restored. At this point the object
431 * validation callbacks are executed in order based on their registered
432 * priorities. The callbacks are registered by objects (in the readObject
433 * special methods) as they are individually restored.
434 *
435 * <p>The deserialization filter, when not {@code null}, is invoked for
436 * each object (regular or class) read to reconstruct the root object.
437 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
438 *
439 * <p>Exceptions are thrown for problems with the InputStream and for
440 * classes that should not be deserialized. All exceptions are fatal to
441 * the InputStream and leave it in an indeterminate state; it is up to the
442 * caller to ignore or recover the stream state.
443 *
444 * <div class="preview-block">
445 * <div class="preview-comment">
446 * <p>An object in the stream that instantiates a concrete
447 * {@linkplain Class#isValue value class}, or that extends a
448 * Serializable abstract value class that declares instance fields,
449 * can only be deserialized if it is a record or a boxed primitive
450 * value. Otherwise, {@code readObject} throws an
451 * {@code InvalidClassException}.
452 * </div>
453 * </div>
454 *
455 * @throws ClassNotFoundException Class of a serialized object cannot be
456 * found.
457 * @throws InvalidClassException Something is wrong with a class used by
458 * deserialization.
459 * @throws StreamCorruptedException Control information in the
460 * stream is inconsistent.
461 * @throws OptionalDataException Primitive data was found in the
462 * stream instead of objects.
463 * @throws IOException Any of the usual Input/Output related exceptions.
464 */
465 public final Object readObject()
466 throws IOException, ClassNotFoundException {
467 return readObject(Object.class);
468 }
469
470 /**
471 * Reads a String and only a string.
472 *
473 * @return the String read
474 * @throws EOFException If end of file is reached.
2127 if (cl == String.class || cl == Class.class
2128 || cl == ObjectStreamClass.class) {
2129 throw new InvalidClassException("invalid class descriptor");
2130 }
2131
2132 Object obj;
2133 try {
2134 obj = desc.isInstantiable() ? desc.newInstance() : null;
2135 } catch (Exception ex) {
2136 throw new InvalidClassException(desc.forClass().getName(),
2137 "unable to create instance", ex);
2138 }
2139
2140 passHandle = handles.assign(unshared ? unsharedMarker : obj);
2141 ClassNotFoundException resolveEx = desc.getResolveException();
2142 if (resolveEx != null) {
2143 handles.markException(passHandle, resolveEx);
2144 }
2145
2146 final boolean isRecord = desc.isRecord();
2147 if (isRecord || desc.hasDeserializer()) {
2148 assert obj == null;
2149 obj = readAlternative(desc);
2150 if (!unshared)
2151 handles.setObject(passHandle, obj);
2152 } else if (desc.isExternalizable()) {
2153 readExternalData((Externalizable) obj, desc);
2154 } else {
2155 readSerialData(obj, desc);
2156 }
2157
2158 handles.finish(passHandle);
2159
2160 if (obj != null &&
2161 handles.lookupException(passHandle) == null &&
2162 desc.hasReadResolveMethod())
2163 {
2164 Object rep = desc.invokeReadResolve(obj);
2165 if (unshared && rep.getClass().isArray()) {
2166 rep = cloneArray(rep);
2167 }
2168 if (rep != obj) {
2169 // Filter the replacement object
2219 } finally {
2220 if (oldContext != null)
2221 oldContext.check();
2222 curContext = oldContext;
2223 }
2224 /*
2225 * At this point, if the externalizable data was not written in
2226 * block-data form and either the externalizable class doesn't exist
2227 * locally (i.e., obj == null) or readExternal() just threw a
2228 * CNFException, then the stream is probably in an inconsistent state,
2229 * since some (or all) of the externalizable data may not have been
2230 * consumed. Since there's no "correct" action to take in this case,
2231 * we mimic the behavior of past serialization implementations and
2232 * blindly hope that the stream is in sync; if it isn't and additional
2233 * externalizable data remains in the stream, a subsequent read will
2234 * most likely throw a StreamCorruptedException.
2235 */
2236 }
2237
2238 /**
2239 * Reads and returns an alternatively-deserialized object, such as a record
2240 * or a wrapper class as a value class.
2241 * If an exception is marked for any of the fields, the dependency
2242 * mechanism marks the object as having an exception.
2243 * Null is returned from readFromFactory and later the exception is thrown at
2244 * the exit of {@link #readObject(Class)}.
2245 */
2246 private Object readAlternative(ObjectStreamClass desc) throws IOException {
2247 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2248 if (slots.length != 1) {
2249 // skip any superclass stream field values
2250 for (int i = 0; i < slots.length-1; i++) {
2251 if (slots[i].hasData) {
2252 new FieldValues(slots[i].desc, true);
2253 }
2254 }
2255 }
2256
2257 FieldValues fieldValues = new FieldValues(desc, true);
2258 if (handles.lookupException(passHandle) != null) {
2259 return null; // slot marked with exception, don't create object
2260 }
2261
2262 // get the factory adapted to take two arguments:
2263 // - byte[] primValues
2264 // - Object[] objValues
2265 // and return Object
2266 MethodHandle factoryMH = AlternativeDeserialization.getFactory(desc);
2267
2268 try {
2269 return (Object) factoryMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2270 } catch (Exception e) {
2271 throw new InvalidObjectException(e.getMessage(), e);
2272 } catch (Error e) {
2273 throw e;
2274 } catch (Throwable t) {
2275 throw new InvalidObjectException("ReflectiveOperationException " +
2276 "during deserialization", t);
2277 }
2278 }
2279
2280 /**
2281 * Reads (or attempts to skip, if obj is null or is tagged with a
2282 * ClassNotFoundException) instance data for each serializable class of
2283 * object in stream, from superclass to subclass. Expects that passHandle
2284 * is set to obj's handle before this method is called.
2285 */
2286 private void readSerialData(Object obj, ObjectStreamClass desc)
2287 throws IOException
2288 {
2289 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
|