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 *
50 * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
51 * and should be avoided. Untrusted data should be carefully validated according to the
52 * "Serialization and Deserialization" section of the
53 * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
54 * {@extLink serialization_filter_guide Serialization Filtering} describes best
55 * practices for defensive use of serial filters.
56 * </strong></p>
57 *
193 * <p>Serialization does not read or assign values to the fields of any object
194 * that does not implement the java.io.Serializable interface. Subclasses of
195 * Objects that are not serializable can be serializable. In this case the
196 * non-serializable class must have a no-arg constructor to allow its fields to
197 * be initialized. In this case it is the responsibility of the subclass to
198 * save and restore the state of the non-serializable class. It is frequently
199 * the case that the fields of that class are accessible (public, package, or
200 * protected) or that there are get and set methods that can be used to restore
201 * the state.
202 *
203 * <p>Any exception that occurs while deserializing an object will be caught by
204 * the ObjectInputStream and abort the reading process.
205 *
206 * <p>Implementing the Externalizable interface allows the object to assume
207 * complete control over the contents and format of the object's serialized
208 * form. The methods of the Externalizable interface, writeExternal and
209 * readExternal, are called to save and restore the objects state. When
210 * implemented by a class they can write and read their own state using all of
211 * the methods of ObjectOutput and ObjectInput. It is the responsibility of
212 * the objects to handle any versioning that occurs.
213 *
214 * <p>Enum constants are deserialized differently than ordinary serializable or
215 * externalizable objects. The serialized form of an enum constant consists
216 * solely of its name; field values of the constant are not transmitted. To
217 * deserialize an enum constant, ObjectInputStream reads the constant name from
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 {
408
409 /**
410 * Read an object from the ObjectInputStream. The class of the object, the
411 * signature of the class, and the values of the non-transient and
412 * non-static fields of the class and all of its supertypes are read.
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
2090 * class is unresolvable (in which case a ClassNotFoundException will be
2091 * associated with object's handle). Sets passHandle to object's assigned
2092 * handle.
2093 */
2094 private Object readOrdinaryObject(boolean unshared)
2095 throws IOException
2096 {
2097 if (bin.readByte() != TC_OBJECT) {
2098 throw new InternalError();
2099 }
2100
2101 ObjectStreamClass desc = readClassDesc(false);
2102 desc.checkDeserialize();
2103
2104 Class<?> cl = desc.forClass();
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
2148 if (rep != null) {
2149 if (rep.getClass().isArray()) {
2150 filterCheck(rep.getClass(), Array.getLength(rep));
2151 } else {
2152 filterCheck(rep.getClass(), -1);
2153 }
2154 }
2155 handles.setObject(passHandle, obj = rep);
2156 }
2157 }
2158
2159 return obj;
2160 }
2161
2162 /**
2163 * If obj is non-null, reads externalizable data by invoking readExternal()
2164 * method of obj; otherwise, attempts to skip over externalizable data.
2165 * Expects that passHandle is set to obj's handle before this method is
2166 * called.
2167 */
2168 private void readExternalData(Externalizable obj, ObjectStreamClass desc)
2169 throws IOException
2170 {
2171 SerialCallbackContext oldContext = curContext;
2172 if (oldContext != null)
2173 oldContext.check();
2174 curContext = null;
2175 try {
2176 boolean blocked = desc.hasBlockExternalData();
2177 if (blocked) {
2178 bin.setBlockDataMode(true);
2179 }
2180 if (obj != null) {
2181 try {
2182 obj.readExternal(this);
2183 } catch (ClassNotFoundException ex) {
2184 /*
2185 * In most cases, the handle table has already propagated
2186 * a CNFException to passHandle at this point; this mark
2187 * call is included to address cases where the readExternal
2188 * method has cons'ed and thrown a new CNFException of its
2189 * own.
2190 */
2194 if (blocked) {
2195 skipCustomData();
2196 }
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();
2267 // Best effort Failure Atomicity; slotValues will be non-null if field
2268 // values can be set after reading all field data in the hierarchy.
2269 // Field values can only be set after reading all data if there are no
2270 // user observable methods in the hierarchy, readObject(NoData). The
2271 // top most Serializable class in the hierarchy can be skipped.
2272 FieldValues[] slotValues = null;
2273
2274 boolean hasSpecialReadMethod = false;
2275 for (int i = 1; i < slots.length; i++) {
2276 ObjectStreamClass slotDesc = slots[i].desc;
2277 if (slotDesc.hasReadObjectMethod()
2278 || slotDesc.hasReadObjectNoDataMethod()) {
2279 hasSpecialReadMethod = true;
2280 break;
2281 }
2282 }
2283 // No special read methods, can store values and defer setting.
2284 if (!hasSpecialReadMethod)
2285 slotValues = new FieldValues[slots.length];
2286
2287 for (int i = 0; i < slots.length; i++) {
2288 ObjectStreamClass slotDesc = slots[i].desc;
2289
2290 if (slots[i].hasData) {
2291 if (obj == null || handles.lookupException(passHandle) != null) {
2292 // Read fields of the current descriptor into a new FieldValues and discard
2293 new FieldValues(slotDesc, true);
2294 } else if (slotDesc.hasReadObjectMethod()) {
2295 SerialCallbackContext oldContext = curContext;
2296 if (oldContext != null)
2297 oldContext.check();
2298 try {
2299 curContext = new SerialCallbackContext(obj, slotDesc);
2300
2301 bin.setBlockDataMode(true);
2302 slotDesc.invokeReadObject(obj, this);
2303 } catch (ClassNotFoundException ex) {
2304 /*
2305 * In most cases, the handle table has already
2306 * propagated a CNFException to passHandle at this
2307 * point; this mark call is included to address cases
2308 * where the custom readObject method has cons'ed and
2309 * thrown a new CNFException of its own.
2310 */
2311 handles.markException(passHandle, ex);
2312 } finally {
2313 curContext.setUsed();
2314 if (oldContext!= null)
2315 oldContext.check();
2316 curContext = oldContext;
2317 }
2318
2319 /*
2320 * defaultDataEnd may have been set indirectly by custom
2321 * readObject() method when calling defaultReadObject() or
2322 * readFields(); clear it to restore normal read behavior.
2323 */
2324 defaultDataEnd = false;
2325 } else {
2326 // Read fields of the current descriptor into a new FieldValues
2327 FieldValues values = new FieldValues(slotDesc, true);
2328 if (slotValues != null) {
2329 slotValues[i] = values;
2330 } else if (obj != null) {
2331 if (handles.lookupException(passHandle) == null) {
2332 // passHandle NOT marked with an exception; set field values
2333 values.defaultCheckFieldValues(obj);
2334 values.defaultSetFieldValues(obj);
2335 }
2336 }
2337 }
2338
2339 if (slotDesc.hasWriteObjectData()) {
2340 skipCustomData();
2341 } else {
2342 bin.setBlockDataMode(false);
2343 }
2344 } else {
2345 if (obj != null &&
2346 slotDesc.hasReadObjectNoDataMethod() &&
2347 handles.lookupException(passHandle) == null)
2348 {
2349 slotDesc.invokeReadObjectNoData(obj);
2350 }
2351 }
2352 }
2353
2354 if (obj != null && slotValues != null && handles.lookupException(passHandle) == null) {
2355 // passHandle NOT marked with an exception
2356 // Check that the non-primitive types are assignable for all slots
2357 // before assigning.
2358 for (int i = 0; i < slots.length; i++) {
2359 if (slotValues[i] != null)
2360 slotValues[i].defaultCheckFieldValues(obj);
2361 }
2362 for (int i = 0; i < slots.length; i++) {
2363 if (slotValues[i] != null)
2364 slotValues[i].defaultSetFieldValues(obj);
2365 }
2366 }
2367 }
2368
2369 /**
2370 * Skips over all block data and objects until TC_ENDBLOCKDATA is
2371 * encountered.
2372 */
2373 private void skipCustomData() throws IOException {
2374 int oldHandle = passHandle;
2375 for (;;) {
2376 if (bin.getBlockDataMode()) {
2377 bin.skipBlockData();
2378 bin.setBlockDataMode(false);
2379 }
2380 switch (bin.peekByte()) {
2381 case TC_BLOCKDATA:
2382 case TC_BLOCKDATALONG:
2383 bin.setBlockDataMode(true);
2384 break;
2385
2441 /**
2442 * Default GetField implementation.
2443 */
2444 private final class FieldValues extends GetField {
2445
2446 /** class descriptor describing serializable fields */
2447 private final ObjectStreamClass desc;
2448 /** primitive field values */
2449 final byte[] primValues;
2450 /** object field values */
2451 final Object[] objValues;
2452 /** object field value handles */
2453 private final int[] objHandles;
2454
2455 /**
2456 * Creates FieldValues object for reading fields defined in given
2457 * class descriptor.
2458 * @param desc the ObjectStreamClass to read
2459 * @param recordDependencies if true, record the dependencies
2460 * from current PassHandle and the object's read.
2461 */
2462 FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws IOException {
2463 this.desc = desc;
2464
2465 int primDataSize = desc.getPrimDataSize();
2466 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2467 if (primDataSize > 0) {
2468 bin.readFully(primValues, 0, primDataSize, false);
2469 }
2470
2471 int numObjFields = desc.getNumObjFields();
2472 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2473 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2474 if (numObjFields > 0) {
2475 int objHandle = passHandle;
2476 ObjectStreamField[] fields = desc.getFields(false);
2477 int numPrimFields = fields.length - objValues.length;
2478 for (int i = 0; i < objValues.length; i++) {
2479 ObjectStreamField f = fields[numPrimFields + i];
2480 objValues[i] = readObject0(Object.class, f.isUnshared());
2481 objHandles[i] = passHandle;
2482 if (recordDependencies && f.getField() != null) {
2483 handles.markDependency(objHandle, passHandle);
2484 }
2485 }
2486 passHandle = objHandle;
2487 }
2488 }
2489
2490 public ObjectStreamClass getObjectStreamClass() {
2491 return desc;
2492 }
2493
2494 public boolean defaulted(String name) {
2495 return (getFieldOffset(name, null) < 0);
2496 }
2497
2498 public boolean get(String name, boolean val) {
2499 int off = getFieldOffset(name, Boolean.TYPE);
2500 return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2501 }
2502
2503 public byte get(String name, byte val) {
2504 int off = getFieldOffset(name, Byte.TYPE);
2505 return (off >= 0) ? primValues[off] : val;
2506 }
|
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.ConstructorSupport;
30 import java.io.ObjectStreamClass.ClassDataSlot;
31 import java.lang.System.Logger;
32 import java.lang.invoke.MethodHandle;
33 import java.lang.reflect.Array;
34 import java.lang.reflect.InvocationHandler;
35 import java.lang.reflect.InvocationTargetException;
36 import java.lang.reflect.Modifier;
37 import java.lang.reflect.Proxy;
38 import java.nio.charset.StandardCharsets;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42 import java.util.Objects;
43
44 import jdk.internal.access.JavaLangAccess;
45 import jdk.internal.access.SharedSecrets;
46 import jdk.internal.event.DeserializationEvent;
47 import jdk.internal.misc.Unsafe;
48 import jdk.internal.util.ByteArray;
49
50 /**
51 * An ObjectInputStream deserializes primitive data and objects previously
52 * written using an ObjectOutputStream.
53 *
54 * <p><strong>Warning: Deserialization of untrusted data is inherently dangerous
55 * and should be avoided. Untrusted data should be carefully validated according to the
56 * "Serialization and Deserialization" section of the
57 * {@extLink secure_coding_guidelines_javase Secure Coding Guidelines for Java SE}.
58 * {@extLink serialization_filter_guide Serialization Filtering} describes best
59 * practices for defensive use of serial filters.
60 * </strong></p>
61 *
197 * <p>Serialization does not read or assign values to the fields of any object
198 * that does not implement the java.io.Serializable interface. Subclasses of
199 * Objects that are not serializable can be serializable. In this case the
200 * non-serializable class must have a no-arg constructor to allow its fields to
201 * be initialized. In this case it is the responsibility of the subclass to
202 * save and restore the state of the non-serializable class. It is frequently
203 * the case that the fields of that class are accessible (public, package, or
204 * protected) or that there are get and set methods that can be used to restore
205 * the state.
206 *
207 * <p>Any exception that occurs while deserializing an object will be caught by
208 * the ObjectInputStream and abort the reading process.
209 *
210 * <p>Implementing the Externalizable interface allows the object to assume
211 * complete control over the contents and format of the object's serialized
212 * form. The methods of the Externalizable interface, writeExternal and
213 * readExternal, are called to save and restore the objects state. When
214 * implemented by a class they can write and read their own state using all of
215 * the methods of ObjectOutput and ObjectInput. It is the responsibility of
216 * the objects to handle any versioning that occurs.
217 * Value objects cannot be `java.io.Externalizable` because value objects are
218 * immutable and `Externalizable.readExternal` is unable to modify the fields of the value.
219 *
220 * <p>Enum constants are deserialized differently than ordinary serializable or
221 * externalizable objects. The serialized form of an enum constant consists
222 * solely of its name; field values of the constant are not transmitted. To
223 * deserialize an enum constant, ObjectInputStream reads the constant name from
224 * the stream; the deserialized constant is then obtained by calling the static
225 * method {@code Enum.valueOf(Class, String)} with the enum constant's
226 * base type and the received constant name as arguments. Like other
227 * serializable or externalizable objects, enum constants can function as the
228 * targets of back references appearing subsequently in the serialization
229 * stream. The process by which enum constants are deserialized cannot be
230 * customized: any class-specific readObject, readObjectNoData, and readResolve
231 * methods defined by enum types are ignored during deserialization.
232 * Similarly, any serialPersistentFields or serialVersionUID field declarations
233 * are also ignored--all enum types have a fixed serialVersionUID of 0L.
234 *
235 * <a id="record-serialization"></a>
236 * <p>Records are serialized differently than ordinary serializable or externalizable
237 * objects. During deserialization the record's canonical constructor is invoked
238 * to construct the record object. Certain serialization-related methods, such
239 * as readObject and writeObject, are ignored for serializable records. See
240 * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
241 * <cite>Java Object Serialization Specification,</cite> Section 1.13,
242 * "Serialization of Records"</a> for additional information.
243 *
244 * <p>Value classes are {@linkplain Serializable} through the use of the serialization proxy pattern.
245 * See {@linkplain ObjectOutputStream##valueclass-serialization value class serialization} for details.
246 * When the proxy is deserialized it re-constructs and returns the value object.
247 *
248 * @spec serialization/index.html Java Object Serialization Specification
249 * @author Mike Warres
250 * @author Roger Riggs
251 * @see java.io.DataInput
252 * @see java.io.ObjectOutputStream
253 * @see java.io.Serializable
254 * @see <a href="{@docRoot}/../specs/serialization/input.html">
255 * <cite>Java Object Serialization Specification,</cite> Section 3, "Object Input Classes"</a>
256 * @since 1.1
257 */
258 public class ObjectInputStream
259 extends InputStream implements ObjectInput, ObjectStreamConstants
260 {
261 /** handle value representing null */
262 private static final int NULL_HANDLE = -1;
263
264 /** marker for unshared objects in internal handle table */
265 private static final Object unsharedMarker = new Object();
266
267 private static class Caches {
418
419 /**
420 * Read an object from the ObjectInputStream. The class of the object, the
421 * signature of the class, and the values of the non-transient and
422 * non-static fields of the class and all of its supertypes are read.
423 * Default deserializing for a class can be overridden using the writeObject
424 * and readObject methods. Objects referenced by this object are read
425 * transitively so that a complete equivalent graph of objects is
426 * reconstructed by readObject.
427 *
428 * <p>The root object is completely restored when all of its fields and the
429 * objects it references are completely restored. At this point the object
430 * validation callbacks are executed in order based on their registered
431 * priorities. The callbacks are registered by objects (in the readObject
432 * special methods) as they are individually restored.
433 *
434 * <p>The deserialization filter, when not {@code null}, is invoked for
435 * each object (regular or class) read to reconstruct the root object.
436 * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
437 *
438 * <p>Serialization and deserialization of value classes is described in
439 * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
440 *
441 * @implSpec
442 * When enabled with {@code --enable-preview}, serialization and deserialization of
443 * Core Library value classes migrated from pre-JEP 401 identity classes is
444 * implementation specific.
445 *
446 * <p>Exceptions are thrown for problems with the InputStream and for
447 * classes that should not be deserialized. All exceptions are fatal to
448 * the InputStream and leave it in an indeterminate state; it is up to the
449 * caller to ignore or recover the stream state.
450 *
451 * @throws ClassNotFoundException Class of a serialized object cannot be
452 * found.
453 * @throws InvalidClassException Something is wrong with a class used by
454 * deserialization.
455 * @throws StreamCorruptedException Control information in the
456 * stream is inconsistent.
457 * @throws OptionalDataException Primitive data was found in the
458 * stream instead of objects.
459 * @throws IOException Any of the usual Input/Output related exceptions.
460 */
461 public final Object readObject()
462 throws IOException, ClassNotFoundException {
463 return readObject(Object.class);
464 }
465
2108 * class is unresolvable (in which case a ClassNotFoundException will be
2109 * associated with object's handle). Sets passHandle to object's assigned
2110 * handle.
2111 */
2112 private Object readOrdinaryObject(boolean unshared)
2113 throws IOException
2114 {
2115 if (bin.readByte() != TC_OBJECT) {
2116 throw new InternalError();
2117 }
2118
2119 ObjectStreamClass desc = readClassDesc(false);
2120 desc.checkDeserialize();
2121
2122 Class<?> cl = desc.forClass();
2123 if (cl == String.class || cl == Class.class
2124 || cl == ObjectStreamClass.class) {
2125 throw new InvalidClassException("invalid class descriptor");
2126 }
2127
2128 // Assign the handle and initially set to null or the unsharedMarker
2129 passHandle = handles.assign(unshared ? unsharedMarker : null);
2130 ClassNotFoundException resolveEx = desc.getResolveException();
2131 if (resolveEx != null) {
2132 handles.markException(passHandle, resolveEx);
2133 }
2134
2135 try {
2136 // Dispatch on the factory mode to read an object from the stream.
2137 Object obj = switch (desc.factoryMode()) {
2138 case READ_OBJECT_DEFAULT -> readSerialDefaultObject(desc, unshared);
2139 case READ_OBJECT_CUSTOM -> readSerialCustomData(desc, unshared);
2140 case READ_RECORD -> readRecord(desc, unshared);
2141 case READ_EXTERNALIZABLE -> readExternalObject(desc, unshared);
2142 case READ_OBJECT_VALUE -> readObjectValue(desc, unshared);
2143 case READ_NO_LOCAL_CLASS -> readAbsentLocalClass(desc, unshared);
2144 case null -> throw new AssertionError("Unknown factoryMode for: " + desc.getName(),
2145 resolveEx);
2146 };
2147
2148 handles.finish(passHandle);
2149
2150 if (obj != null &&
2151 handles.lookupException(passHandle) == null &&
2152 desc.hasReadResolveMethod())
2153 {
2154 Object rep = desc.invokeReadResolve(obj);
2155 if (unshared && rep.getClass().isArray()) {
2156 rep = cloneArray(rep);
2157 }
2158 if (rep != obj) {
2159 // Filter the replacement object
2160 if (rep != null) {
2161 if (rep.getClass().isArray()) {
2162 filterCheck(rep.getClass(), Array.getLength(rep));
2163 } else {
2164 filterCheck(rep.getClass(), -1);
2165 }
2166 }
2167 handles.setObject(passHandle, obj = rep);
2168 }
2169 }
2170
2171 return obj;
2172 } catch (UncheckedIOException uioe) {
2173 // Consistent re-throw for nested UncheckedIOExceptions
2174 throw uioe.getCause();
2175 }
2176 }
2177
2178 /**
2179 * {@return a value class instance by invoking its constructor with field values read from the stream.
2180 * The fields of the class in the stream are matched to the local fields and applied to
2181 * the constructor.
2182 * If the stream contains superclasses with serializable fields,
2183 * an InvalidClassException is thrown with an incompatible class change message.
2184 *
2185 * @param desc the class descriptor read from the stream, the local class is a value class
2186 * @param unshared if the object is not to be shared
2187 * @throws InvalidClassException if the stream contains a superclass with serializable fields.
2188 * @throws IOException if there are I/O errors while reading from the
2189 * underlying {@code InputStream}
2190 */
2191 private Object readObjectValue(ObjectStreamClass desc, boolean unshared) throws IOException {
2192 final ObjectStreamClass localDesc = desc.getLocalDesc();
2193 // Check for un-expected fields in superclasses
2194 List<ClassDataSlot> slots = desc.getClassDataLayout();
2195 for (int i = 0; i < slots.size()-1; i++) {
2196 ClassDataSlot slot = slots.get(i);
2197 if (slot.hasData && slot.desc.getFields(false).length > 0) {
2198 throw new InvalidClassException("incompatible class change to value class: " +
2199 "stream class has non-empty super type: " + desc.getName());
2200 }
2201 }
2202 // Read values for the value class fields
2203 FieldValues fieldValues = new FieldValues(desc, true);
2204
2205 // Get value object constructor adapted to take primitive value buffer and object array.
2206 MethodHandle consMH = ConstructorSupport.deserializationValueCons(desc);
2207 try {
2208 Object obj = (Object) consMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2209 if (!unshared)
2210 handles.setObject(passHandle, obj);
2211 return obj;
2212 } catch (Exception e) {
2213 throw new InvalidObjectException(e.getMessage(), e);
2214 } catch (Error e) {
2215 throw e;
2216 } catch (Throwable t) {
2217 throw new InvalidObjectException("ReflectiveOperationException " +
2218 "during deserialization", t);
2219 }
2220 }
2221
2222 /**
2223 * Creates a new object and invokes its readExternal method to read its contents.
2224 *
2225 * If the class is instantiable, read externalizable data by invoking readExternal()
2226 * method of obj; otherwise, attempts to skip over externalizable data.
2227 * Expects that passHandle is set to obj's handle before this method is
2228 * called. The new object is entered in the handle table immediately,
2229 * allowing it to leak before it is completely read.
2230 */
2231 private Object readExternalObject(ObjectStreamClass desc, boolean unshared)
2232 throws IOException
2233 {
2234 // For Externalizable objects,
2235 // create the instance, publish the ref, and read the data
2236 Externalizable obj = null;
2237 try {
2238 if (desc.isInstantiable()) {
2239 obj = (Externalizable) desc.newInstance();
2240 }
2241 } catch (Exception ex) {
2242 throw new InvalidClassException(desc.getName(),
2243 "unable to create instance", ex);
2244 }
2245
2246 if (!unshared)
2247 handles.setObject(passHandle, obj);
2248
2249 SerialCallbackContext oldContext = curContext;
2250 if (oldContext != null)
2251 oldContext.check();
2252 curContext = null;
2253 try {
2254 boolean blocked = desc.hasBlockExternalData();
2255 if (blocked) {
2256 bin.setBlockDataMode(true);
2257 }
2258 if (obj != null) {
2259 try {
2260 obj.readExternal(this);
2261 } catch (ClassNotFoundException ex) {
2262 /*
2263 * In most cases, the handle table has already propagated
2264 * a CNFException to passHandle at this point; this mark
2265 * call is included to address cases where the readExternal
2266 * method has cons'ed and thrown a new CNFException of its
2267 * own.
2268 */
2272 if (blocked) {
2273 skipCustomData();
2274 }
2275 } finally {
2276 if (oldContext != null)
2277 oldContext.check();
2278 curContext = oldContext;
2279 }
2280 /*
2281 * At this point, if the externalizable data was not written in
2282 * block-data form and either the externalizable class doesn't exist
2283 * locally (i.e., obj == null) or readExternal() just threw a
2284 * CNFException, then the stream is probably in an inconsistent state,
2285 * since some (or all) of the externalizable data may not have been
2286 * consumed. Since there's no "correct" action to take in this case,
2287 * we mimic the behavior of past serialization implementations and
2288 * blindly hope that the stream is in sync; if it isn't and additional
2289 * externalizable data remains in the stream, a subsequent read will
2290 * most likely throw a StreamCorruptedException.
2291 */
2292 return obj;
2293 }
2294
2295 /**
2296 * Reads and returns a record.
2297 * If an exception is marked for any of the fields, the dependency
2298 * mechanism marks the record as having an exception.
2299 * Null is returned from readRecord and later the exception is thrown at
2300 * the exit of {@link #readObject(Class)}.
2301 */
2302 private Object readRecord(ObjectStreamClass desc, boolean unshared) throws IOException {
2303 List<ClassDataSlot> slots = desc.getClassDataLayout();
2304 if (slots.size() != 1) {
2305 // skip any superclass stream field values
2306 for (int i = 0; i < slots.size()-1; i++) {
2307 if (slots.get(i).hasData) {
2308 new FieldValues(slots.get(i).desc, true);
2309 }
2310 }
2311 }
2312
2313 FieldValues fieldValues = new FieldValues(desc, true);
2314 if (handles.lookupException(passHandle) != null) {
2315 return null; // slot marked with exception, don't create record
2316 }
2317
2318 // get canonical record constructor adapted to take two arguments:
2319 // - byte[] primValues
2320 // - Object[] objValues
2321 // and return Object
2322 MethodHandle ctrMH = ConstructorSupport.deserializationCtr(desc);
2323
2324 try {
2325 Object obj = (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2326 if (!unshared)
2327 handles.setObject(passHandle, obj);
2328 return obj;
2329 } catch (Exception e) {
2330 throw new InvalidObjectException(e.getMessage(), e);
2331 } catch (Error e) {
2332 throw e;
2333 } catch (Throwable t) {
2334 throw new InvalidObjectException("ReflectiveOperationException " +
2335 "during deserialization", t);
2336 }
2337 }
2338
2339 /**
2340 * Construct an object from the stream for a class that has only default read object behaviors.
2341 * For each object, the fields are read before any are assigned.
2342 * The new instance is entered in the handle table if it is unshared,
2343 * allowing it to escape before it is initialized.
2344 * The `readObject` and `readObjectNoData` methods are not present and are not called.
2345 *
2346 * @param desc the class descriptor
2347 * @param unshared true if the object should be shared
2348 * @return the object constructed from the stream data
2349 * @throws IOException if there are I/O errors while reading from the
2350 * underlying {@code InputStream}
2351 * @throws InvalidClassException if the instance creation fails
2352 */
2353 private Object readSerialDefaultObject(ObjectStreamClass desc, boolean unshared)
2354 throws IOException, InvalidClassException {
2355 if (!desc.isInstantiable()) {
2356 // No local class to create, read and discard
2357 return readAbsentLocalClass(desc, unshared);
2358 }
2359 try {
2360 final Object obj = desc.newInstance();
2361 if (!unshared)
2362 handles.setObject(passHandle, obj);
2363
2364 // Best effort Failure Atomicity; slotValues will be non-null if field
2365 // values can be set after reading all field data in the hierarchy.
2366 List<ClassDataSlot> slots = desc.getClassDataLayout();
2367 List<FieldValues> slotValues = new ArrayList<>(slots.size());
2368 for (ClassDataSlot s : slots) {
2369 if (s.hasData) {
2370 var value = new FieldValues(s.desc, true);
2371 finishBlockData(s.desc);
2372 slotValues.add(value);
2373 }
2374 }
2375
2376 if (handles.lookupException(passHandle) != null) {
2377 return null; // some exception for a class, do not return the object
2378 }
2379
2380 // Check that the types are assignable for all slots before assigning.
2381 for (FieldValues slotValue : slotValues) {
2382 slotValue.defaultCheckFieldValues(obj);
2383 }
2384 for (FieldValues v : slotValues) {
2385 v.defaultSetFieldValues(obj);
2386 }
2387 return obj;
2388 } catch (InstantiationException | InvocationTargetException ex) {
2389 throw new InvalidClassException(desc.forClass().getName(),
2390 "unable to create instance", ex);
2391 }
2392 }
2393
2394
2395 /**
2396 * Reads (or attempts to skip, if not instantiatable or is tagged with a
2397 * ClassNotFoundException) instance data for each serializable class of
2398 * object in stream, from superclass to subclass.
2399 * Expects that passHandle is set to current handle before this method is called.
2400 */
2401 private Object readSerialCustomData(ObjectStreamClass desc, boolean unshared)
2402 throws IOException
2403 {
2404 if (!desc.isInstantiable()) {
2405 // No local class to create, read and discard
2406 return readAbsentLocalClass(desc, unshared);
2407 }
2408
2409 try {
2410 Object obj = desc.newInstance();
2411 if (!unshared)
2412 handles.setObject(passHandle, obj);
2413 // Read data into each of the slots for the class
2414 return readSerialCustomSlots(obj, desc.getClassDataLayout());
2415 } catch (InstantiationException | InvocationTargetException ex) {
2416 throw new InvalidClassException(desc.forClass().getName(),
2417 "unable to create instance", ex);
2418 }
2419 }
2420
2421 /**
2422 * Reads from the stream using custom or default readObject methods appropriate.
2423 * For each slot, either the custom readObject method or the default reader of fields
2424 * is invoked. Unused slot specific custom data is discarded.
2425 * This function is used by {@link #readSerialCustomData}.
2426 *
2427 * @param obj the object to assign the values to
2428 * @param slots a list of slots to read from the stream
2429 * @return the object being initialized
2430 * @throws IOException if there are I/O errors while reading from the
2431 * underlying {@code InputStream}
2432 */
2433 private Object readSerialCustomSlots(Object obj, List<ClassDataSlot> slots) throws IOException {
2434
2435 for (ClassDataSlot slot : slots) {
2436 ObjectStreamClass slotDesc = slot.desc;
2437 if (slot.hasData) {
2438 if (slotDesc.hasReadObjectMethod() &&
2439 handles.lookupException(passHandle) == null) {
2440 // Invoke slot custom readObject method
2441 readSlotViaReadObject(obj, slotDesc);
2442 } else {
2443 // Read fields of the current descriptor into a new FieldValues
2444 FieldValues values = new FieldValues(slotDesc, true);
2445 if (handles.lookupException(passHandle) == null) {
2446 // Set the instance fields if no previous exception
2447 values.defaultCheckFieldValues(obj);
2448 values.defaultSetFieldValues(obj);
2449 }
2450 finishBlockData(slotDesc);
2451 }
2452 } else {
2453 if (slotDesc.hasReadObjectNoDataMethod() &&
2454 handles.lookupException(passHandle) == null) {
2455 slotDesc.invokeReadObjectNoData(obj);
2456 }
2457 }
2458 }
2459 return obj;
2460 }
2461
2462 /**
2463 * Invoke the readObject method of the class to read and store the state from the stream.
2464 *
2465 * @param obj an instance of the class being created, only partially initialized.
2466 * @param slotDesc the ObjectStreamDescriptor for the current class
2467 * @throws IOException if there are I/O errors while reading from the
2468 * underlying {@code InputStream}
2469 */
2470 private void readSlotViaReadObject(Object obj, ObjectStreamClass slotDesc) throws IOException {
2471 assert obj != null : "readSlotViaReadObject called when obj == null";
2472
2473 SerialCallbackContext oldContext = curContext;
2474 if (oldContext != null)
2475 oldContext.check();
2476 try {
2477 curContext = new SerialCallbackContext(obj, slotDesc);
2478
2479 bin.setBlockDataMode(true);
2480 slotDesc.invokeReadObject(obj, this);
2481 } catch (ClassNotFoundException ex) {
2482 /*
2483 * In most cases, the handle table has already
2484 * propagated a CNFException to passHandle at this
2485 * point; this mark call is included to address cases
2486 * where the custom readObject method has cons'ed and
2487 * thrown a new CNFException of its own.
2488 */
2489 handles.markException(passHandle, ex);
2490 } finally {
2491 curContext.setUsed();
2492 if (oldContext!= null)
2493 oldContext.check();
2494 curContext = oldContext;
2495 }
2496
2497 /*
2498 * defaultDataEnd may have been set indirectly by custom
2499 * readObject() method when calling defaultReadObject() or
2500 * readFields(); clear it to restore normal read behavior.
2501 */
2502 defaultDataEnd = false;
2503
2504 finishBlockData(slotDesc);
2505 }
2506
2507
2508 /**
2509 * Read and discard an entire object, leaving a null reference in the HandleTable.
2510 * The descriptor of the class in the stream is used to read the fields from the stream.
2511 * There is no instance in which to store the field values.
2512 * Custom data following the fields of any slot is read and discarded.
2513 * References to nested objects are read and retained in the
2514 * handle table using the regular mechanism.
2515 * Handles later in the stream may refer to the nested objects.
2516 *
2517 * @param desc the stream class descriptor
2518 * @param unshared the unshared flag, ignored since no object is created
2519 * @return null, no object is created
2520 * @throws IOException if there are I/O errors while reading from the
2521 * underlying {@code InputStream}
2522 */
2523 private Object readAbsentLocalClass(ObjectStreamClass desc, boolean unshared)
2524 throws IOException {
2525 desc.getClassDataLayout().stream()
2526 .filter(s -> s.hasData)
2527 .forEach(s2 -> {new FieldValues(s2.desc, true); finishBlockData(s2.desc);});
2528 return null;
2529 }
2530
2531 // Finish handling of block data by skipping any remaining and setting BlockDataMode = false
2532 private void finishBlockData(ObjectStreamClass slotDesc) throws UncheckedIOException {
2533 try {
2534 if (slotDesc.hasWriteObjectData()) {
2535 skipCustomData();
2536 } else {
2537 bin.setBlockDataMode(false);
2538 }
2539 } catch (IOException ioe) {
2540 throw new UncheckedIOException(ioe);
2541 }
2542 }
2543
2544 /**
2545 * Skips over all block data and objects until TC_ENDBLOCKDATA is
2546 * encountered.
2547 */
2548 private void skipCustomData() throws IOException {
2549 int oldHandle = passHandle;
2550 for (;;) {
2551 if (bin.getBlockDataMode()) {
2552 bin.skipBlockData();
2553 bin.setBlockDataMode(false);
2554 }
2555 switch (bin.peekByte()) {
2556 case TC_BLOCKDATA:
2557 case TC_BLOCKDATALONG:
2558 bin.setBlockDataMode(true);
2559 break;
2560
2616 /**
2617 * Default GetField implementation.
2618 */
2619 private final class FieldValues extends GetField {
2620
2621 /** class descriptor describing serializable fields */
2622 private final ObjectStreamClass desc;
2623 /** primitive field values */
2624 final byte[] primValues;
2625 /** object field values */
2626 final Object[] objValues;
2627 /** object field value handles */
2628 private final int[] objHandles;
2629
2630 /**
2631 * Creates FieldValues object for reading fields defined in given
2632 * class descriptor.
2633 * @param desc the ObjectStreamClass to read
2634 * @param recordDependencies if true, record the dependencies
2635 * from current PassHandle and the object's read.
2636 * @throws UncheckedIOException if any IOException occurs
2637 */
2638 FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws UncheckedIOException {
2639 try {
2640 this.desc = desc;
2641 int primDataSize = desc.getPrimDataSize();
2642 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2643 if (primDataSize > 0) {
2644 bin.readFully(primValues, 0, primDataSize, false);
2645 }
2646
2647
2648 int numObjFields = desc.getNumObjFields();
2649 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2650 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2651 if (numObjFields > 0) {
2652 int objHandle = passHandle;
2653 ObjectStreamField[] fields = desc.getFields(false);
2654 int numPrimFields = fields.length - objValues.length;
2655 for (int i = 0; i < objValues.length; i++) {
2656 ObjectStreamField f = fields[numPrimFields + i];
2657 objValues[i] = readObject0(Object.class, f.isUnshared());
2658 objHandles[i] = passHandle;
2659 if (recordDependencies && f.getField() != null) {
2660 handles.markDependency(objHandle, passHandle);
2661 }
2662 }
2663 passHandle = objHandle;
2664 }
2665 } catch (IOException ioe) {
2666 throw new UncheckedIOException(ioe);
2667 }
2668 }
2669
2670 public ObjectStreamClass getObjectStreamClass() {
2671 return desc;
2672 }
2673
2674 public boolean defaulted(String name) {
2675 return (getFieldOffset(name, null) < 0);
2676 }
2677
2678 public boolean get(String name, boolean val) {
2679 int off = getFieldOffset(name, Boolean.TYPE);
2680 return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2681 }
2682
2683 public byte get(String name, byte val) {
2684 int off = getFieldOffset(name, Byte.TYPE);
2685 return (off >= 0) ? primValues[off] : val;
2686 }
|