< prev index next >

src/java.base/share/classes/java/io/ObjectInputStream.java

Print this page

   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();
< prev index next >