< prev index next >

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

Print this page

   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 {
 258         /** cache of subclass security audit results */
 259         static final ClassValue<Boolean> subclassAudits =
 260             new ClassValue<>() {
 261                 @Override
 262                 protected Boolean computeValue(Class<?> type) {
 263                     return auditSubclass(type);
 264                 }
 265             };
 266 
 267         /**
 268          * Property to permit setting a filter after objects
 269          * have been read.
 270          * See {@link #setObjectInputFilter(ObjectInputFilter)}

 416 
 417     /**
 418      * Read an object from the ObjectInputStream.  The class of the object, the
 419      * signature of the class, and the values of the non-transient and
 420      * non-static fields of the class and all of its supertypes are read.
 421      * Default deserializing for a class can be overridden using the writeObject
 422      * and readObject methods.  Objects referenced by this object are read
 423      * transitively so that a complete equivalent graph of objects is
 424      * reconstructed by readObject.
 425      *
 426      * <p>The root object is completely restored when all of its fields and the
 427      * objects it references are completely restored.  At this point the object
 428      * validation callbacks are executed in order based on their registered
 429      * priorities. The callbacks are registered by objects (in the readObject
 430      * special methods) as they are individually restored.
 431      *
 432      * <p>The deserialization filter, when not {@code null}, is invoked for
 433      * each object (regular or class) read to reconstruct the root object.
 434      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 435      *








 436      * <p>Exceptions are thrown for problems with the InputStream and for
 437      * classes that should not be deserialized.  All exceptions are fatal to
 438      * the InputStream and leave it in an indeterminate state; it is up to the
 439      * caller to ignore or recover the stream state.
 440      *
 441      * @throws  ClassNotFoundException Class of a serialized object cannot be
 442      *          found.
 443      * @throws  InvalidClassException Something is wrong with a class used by
 444      *          deserialization.
 445      * @throws  StreamCorruptedException Control information in the
 446      *          stream is inconsistent.
 447      * @throws  OptionalDataException Primitive data was found in the
 448      *          stream instead of objects.
 449      * @throws  IOException Any of the usual Input/Output related exceptions.
 450      */
 451     public final Object readObject()
 452         throws IOException, ClassNotFoundException {
 453         return readObject(Object.class);
 454     }
 455 

2123      * class is unresolvable (in which case a ClassNotFoundException will be
2124      * associated with object's handle).  Sets passHandle to object's assigned
2125      * handle.
2126      */
2127     private Object readOrdinaryObject(boolean unshared)
2128         throws IOException
2129     {
2130         if (bin.readByte() != TC_OBJECT) {
2131             throw new InternalError();
2132         }
2133 
2134         ObjectStreamClass desc = readClassDesc(false);
2135         desc.checkDeserialize();
2136 
2137         Class<?> cl = desc.forClass();
2138         if (cl == String.class || cl == Class.class
2139                 || cl == ObjectStreamClass.class) {
2140             throw new InvalidClassException("invalid class descriptor");
2141         }
2142 
2143         Object obj;
2144         try {
2145             obj = desc.isInstantiable() ? desc.newInstance() : null;
2146         } catch (Exception ex) {
2147             throw new InvalidClassException(desc.forClass().getName(),
2148                                             "unable to create instance", ex);
2149         }
2150 
2151         passHandle = handles.assign(unshared ? unsharedMarker : obj);
2152         ClassNotFoundException resolveEx = desc.getResolveException();
2153         if (resolveEx != null) {
2154             handles.markException(passHandle, resolveEx);
2155         }
2156 
2157         final boolean isRecord = desc.isRecord();
2158         if (isRecord) {
2159             assert obj == null;
2160             obj = readRecord(desc);
2161             if (!unshared)
2162                 handles.setObject(passHandle, obj);
2163         } else if (desc.isExternalizable()) {
2164             readExternalData((Externalizable) obj, desc);
2165         } else {
2166             readSerialData(obj, desc);
2167         }

2168 
2169         handles.finish(passHandle);
2170 
2171         if (obj != null &&
2172             handles.lookupException(passHandle) == null &&
2173             desc.hasReadResolveMethod())
2174         {
2175             Object rep = desc.invokeReadResolve(obj);
2176             if (unshared && rep.getClass().isArray()) {
2177                 rep = cloneArray(rep);
2178             }
2179             if (rep != obj) {
2180                 // Filter the replacement object
2181                 if (rep != null) {
2182                     if (rep.getClass().isArray()) {
2183                         filterCheck(rep.getClass(), Array.getLength(rep));
2184                     } else {
2185                         filterCheck(rep.getClass(), -1);

2186                     }

2187                 }
2188                 handles.setObject(passHandle, obj = rep);
2189             }





2190         }

2191 
2192         return obj;










































2193     }
2194 
2195     /**
2196      * If obj is non-null, reads externalizable data by invoking readExternal()


2197      * method of obj; otherwise, attempts to skip over externalizable data.
2198      * Expects that passHandle is set to obj's handle before this method is
2199      * called.

2200      */
2201     private void readExternalData(Externalizable obj, ObjectStreamClass desc)
2202         throws IOException
2203     {

















2204         SerialCallbackContext oldContext = curContext;
2205         if (oldContext != null)
2206             oldContext.check();
2207         curContext = null;
2208         try {
2209             boolean blocked = desc.hasBlockExternalData();
2210             if (blocked) {
2211                 bin.setBlockDataMode(true);
2212             }
2213             if (obj != null) {
2214                 try {
2215                     obj.readExternal(this);
2216                 } catch (ClassNotFoundException ex) {
2217                     /*
2218                      * In most cases, the handle table has already propagated
2219                      * a CNFException to passHandle at this point; this mark
2220                      * call is included to address cases where the readExternal
2221                      * method has cons'ed and thrown a new CNFException of its
2222                      * own.
2223                      */

2227             if (blocked) {
2228                 skipCustomData();
2229             }
2230         } finally {
2231             if (oldContext != null)
2232                 oldContext.check();
2233             curContext = oldContext;
2234         }
2235         /*
2236          * At this point, if the externalizable data was not written in
2237          * block-data form and either the externalizable class doesn't exist
2238          * locally (i.e., obj == null) or readExternal() just threw a
2239          * CNFException, then the stream is probably in an inconsistent state,
2240          * since some (or all) of the externalizable data may not have been
2241          * consumed.  Since there's no "correct" action to take in this case,
2242          * we mimic the behavior of past serialization implementations and
2243          * blindly hope that the stream is in sync; if it isn't and additional
2244          * externalizable data remains in the stream, a subsequent read will
2245          * most likely throw a StreamCorruptedException.
2246          */

2247     }
2248 
2249     /**
2250      * Reads and returns a record.
2251      * If an exception is marked for any of the fields, the dependency
2252      * mechanism marks the record as having an exception.
2253      * Null is returned from readRecord and later the exception is thrown at
2254      * the exit of {@link #readObject(Class)}.
2255      **/
2256     private Object readRecord(ObjectStreamClass desc) throws IOException {
2257         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2258         if (slots.length != 1) {

2259             // skip any superclass stream field values
2260             for (int i = 0; i < slots.length-1; i++) {
2261                 if (slots[i].hasData) {
2262                     new FieldValues(slots[i].desc, true);
2263                 }
2264             }
2265         }
2266 
2267         FieldValues fieldValues = new FieldValues(desc, true);
2268         if (handles.lookupException(passHandle) != null) {
2269             return null;     // slot marked with exception, don't create record
2270         }
2271 
2272         // get canonical record constructor adapted to take two arguments:
2273         // - byte[] primValues
2274         // - Object[] objValues
2275         // and return Object
2276         MethodHandle ctrMH = RecordSupport.deserializationCtr(desc);
2277 
2278         try {
2279             return (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);



2280         } catch (Exception e) {
2281             throw new InvalidObjectException(e.getMessage(), e);
2282         } catch (Error e) {
2283             throw e;
2284         } catch (Throwable t) {
2285             throw new InvalidObjectException("ReflectiveOperationException " +
2286                                              "during deserialization", t);
2287         }
2288     }
2289 
2290     /**
2291      * Reads (or attempts to skip, if obj is null or is tagged with a




















































2292      * ClassNotFoundException) instance data for each serializable class of
2293      * object in stream, from superclass to subclass.  Expects that passHandle
2294      * is set to obj's handle before this method is called.
2295      */
2296     private void readSerialData(Object obj, ObjectStreamClass desc)
2297         throws IOException
2298     {
2299         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
2300         // Best effort Failure Atomicity; slotValues will be non-null if field
2301         // values can be set after reading all field data in the hierarchy.
2302         // Field values can only be set after reading all data if there are no
2303         // user observable methods in the hierarchy, readObject(NoData). The
2304         // top most Serializable class in the hierarchy can be skipped.
2305         FieldValues[] slotValues = null;
2306 
2307         boolean hasSpecialReadMethod = false;
2308         for (int i = 1; i < slots.length; i++) {
2309             ObjectStreamClass slotDesc = slots[i].desc;
2310             if (slotDesc.hasReadObjectMethod()
2311                   || slotDesc.hasReadObjectNoDataMethod()) {
2312                 hasSpecialReadMethod = true;
2313                 break;
2314             }
2315         }
2316         // No special read methods, can store values and defer setting.
2317         if (!hasSpecialReadMethod)
2318             slotValues = new FieldValues[slots.length];
2319 
2320         for (int i = 0; i < slots.length; i++) {
2321             ObjectStreamClass slotDesc = slots[i].desc;
2322 
2323             if (slots[i].hasData) {
2324                 if (obj == null || handles.lookupException(passHandle) != null) {
2325                     // Read fields of the current descriptor into a new FieldValues and discard
2326                     new FieldValues(slotDesc, true);
2327                 } else if (slotDesc.hasReadObjectMethod()) {
2328                     SerialCallbackContext oldContext = curContext;
2329                     if (oldContext != null)
2330                         oldContext.check();
2331                     try {
2332                         curContext = new SerialCallbackContext(obj, slotDesc);
2333 
2334                         bin.setBlockDataMode(true);
2335                         slotDesc.invokeReadObject(obj, this);
2336                     } catch (ClassNotFoundException ex) {
2337                         /*
2338                          * In most cases, the handle table has already
2339                          * propagated a CNFException to passHandle at this
2340                          * point; this mark call is included to address cases
2341                          * where the custom readObject method has cons'ed and
2342                          * thrown a new CNFException of its own.
2343                          */
2344                         handles.markException(passHandle, ex);
2345                     } finally {
2346                         curContext.setUsed();
2347                         if (oldContext!= null)
2348                             oldContext.check();
2349                         curContext = oldContext;
2350                     }
2351 
2352                     /*
2353                      * defaultDataEnd may have been set indirectly by custom
2354                      * readObject() method when calling defaultReadObject() or
2355                      * readFields(); clear it to restore normal read behavior.
2356                      */
2357                     defaultDataEnd = false;
















2358                 } else {
2359                     // Read fields of the current descriptor into a new FieldValues
2360                     FieldValues values = new FieldValues(slotDesc, true);
2361                     if (slotValues != null) {
2362                         slotValues[i] = values;
2363                     } else if (obj != null) {
2364                         if (handles.lookupException(passHandle) == null) {
2365                             // passHandle NOT marked with an exception; set field values
2366                             values.defaultCheckFieldValues(obj);
2367                             values.defaultSetFieldValues(obj);
2368                         }
2369                     }
2370                 }
2371 
2372                 if (slotDesc.hasWriteObjectData()) {
2373                     skipCustomData();
2374                 } else {
2375                     bin.setBlockDataMode(false);
2376                 }
2377             } else {
2378                 if (obj != null &&
2379                     slotDesc.hasReadObjectNoDataMethod() &&
2380                     handles.lookupException(passHandle) == null)
2381                 {
2382                     slotDesc.invokeReadObjectNoData(obj);
2383                 }
2384             }
2385         }


2386 
2387         if (obj != null && slotValues != null && handles.lookupException(passHandle) == null) {
2388             // passHandle NOT marked with an exception
2389             // Check that the non-primitive types are assignable for all slots
2390             // before assigning.
2391             for (int i = 0; i < slots.length; i++) {
2392                 if (slotValues[i] != null)
2393                     slotValues[i].defaultCheckFieldValues(obj);
2394             }
2395             for (int i = 0; i < slots.length; i++) {
2396                 if (slotValues[i] != null)
2397                     slotValues[i].defaultSetFieldValues(obj);



































































2398             }


2399         }
2400     }
2401 
2402     /**
2403      * Skips over all block data and objects until TC_ENDBLOCKDATA is
2404      * encountered.
2405      */
2406     private void skipCustomData() throws IOException {
2407         int oldHandle = passHandle;
2408         for (;;) {
2409             if (bin.getBlockDataMode()) {
2410                 bin.skipBlockData();
2411                 bin.setBlockDataMode(false);
2412             }
2413             switch (bin.peekByte()) {
2414                 case TC_BLOCKDATA:
2415                 case TC_BLOCKDATALONG:
2416                     bin.setBlockDataMode(true);
2417                     break;
2418 

2474     /**
2475      * Default GetField implementation.
2476      */
2477     private final class FieldValues extends GetField {
2478 
2479         /** class descriptor describing serializable fields */
2480         private final ObjectStreamClass desc;
2481         /** primitive field values */
2482         final byte[] primValues;
2483         /** object field values */
2484         final Object[] objValues;
2485         /** object field value handles */
2486         private final int[] objHandles;
2487 
2488         /**
2489          * Creates FieldValues object for reading fields defined in given
2490          * class descriptor.
2491          * @param desc the ObjectStreamClass to read
2492          * @param recordDependencies if true, record the dependencies
2493          *                           from current PassHandle and the object's read.

2494          */
2495         FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws IOException {
2496             this.desc = desc;







2497 
2498             int primDataSize = desc.getPrimDataSize();
2499             primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2500             if (primDataSize > 0) {
2501                 bin.readFully(primValues, 0, primDataSize, false);
2502             }
2503 
2504             int numObjFields = desc.getNumObjFields();
2505             objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2506             objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2507             if (numObjFields > 0) {
2508                 int objHandle = passHandle;
2509                 ObjectStreamField[] fields = desc.getFields(false);
2510                 int numPrimFields = fields.length - objValues.length;
2511                 for (int i = 0; i < objValues.length; i++) {
2512                     ObjectStreamField f = fields[numPrimFields + i];
2513                     objValues[i] = readObject0(Object.class, f.isUnshared());
2514                     objHandles[i] = passHandle;
2515                     if (recordDependencies && f.getField() != null) {
2516                         handles.markDependency(objHandle, passHandle);

2517                     }

2518                 }
2519                 passHandle = objHandle;

2520             }
2521         }
2522 
2523         public ObjectStreamClass getObjectStreamClass() {
2524             return desc;
2525         }
2526 
2527         public boolean defaulted(String name) {
2528             return (getFieldOffset(name, null) < 0);
2529         }
2530 
2531         public boolean get(String name, boolean val) {
2532             int off = getFieldOffset(name, Boolean.TYPE);
2533             return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2534         }
2535 
2536         public byte get(String name, byte val) {
2537             int off = getFieldOffset(name, Byte.TYPE);
2538             return (off >= 0) ? primValues[off] : val;
2539         }

   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.Arrays;
  40 import java.util.List;
  41 import java.util.Locale;
  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     private static final String TRACE_DEST =
 262             System.getProperty("TRACE");
 263 
 264     static void TRACE(String format, Object... args) {
 265         if (TRACE_DEST != null) {
 266             var ps = "OUT".equals(TRACE_DEST.toUpperCase(Locale.ROOT)) ? System.out : System.err;
 267             ps.println(("TRACE " + format).formatted(args));
 268         }
 269     }
 270 
 271     /** handle value representing null */
 272     private static final int NULL_HANDLE = -1;
 273 
 274     /** marker for unshared objects in internal handle table */
 275     private static final Object unsharedMarker = new Object();
 276 
 277     private static class Caches {
 278         /** cache of subclass security audit results */
 279         static final ClassValue<Boolean> subclassAudits =
 280             new ClassValue<>() {
 281                 @Override
 282                 protected Boolean computeValue(Class<?> type) {
 283                     return auditSubclass(type);
 284                 }
 285             };
 286 
 287         /**
 288          * Property to permit setting a filter after objects
 289          * have been read.
 290          * See {@link #setObjectInputFilter(ObjectInputFilter)}

 436 
 437     /**
 438      * Read an object from the ObjectInputStream.  The class of the object, the
 439      * signature of the class, and the values of the non-transient and
 440      * non-static fields of the class and all of its supertypes are read.
 441      * Default deserializing for a class can be overridden using the writeObject
 442      * and readObject methods.  Objects referenced by this object are read
 443      * transitively so that a complete equivalent graph of objects is
 444      * reconstructed by readObject.
 445      *
 446      * <p>The root object is completely restored when all of its fields and the
 447      * objects it references are completely restored.  At this point the object
 448      * validation callbacks are executed in order based on their registered
 449      * priorities. The callbacks are registered by objects (in the readObject
 450      * special methods) as they are individually restored.
 451      *
 452      * <p>The deserialization filter, when not {@code null}, is invoked for
 453      * each object (regular or class) read to reconstruct the root object.
 454      * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
 455      *
 456      * <p>Serialization and deserialization of value classes is described in
 457      * {@linkplain ObjectOutputStream##valueclass-serialization value class serialization}.
 458      *
 459      * @implSpec
 460      * When enabled with {@code --enable-preview}, serialization and deserialization of
 461      * Core Library value classes migrated from pre-JEP 401 identity classes is
 462      * implementation specific.
 463      *
 464      * <p>Exceptions are thrown for problems with the InputStream and for
 465      * classes that should not be deserialized.  All exceptions are fatal to
 466      * the InputStream and leave it in an indeterminate state; it is up to the
 467      * caller to ignore or recover the stream state.
 468      *
 469      * @throws  ClassNotFoundException Class of a serialized object cannot be
 470      *          found.
 471      * @throws  InvalidClassException Something is wrong with a class used by
 472      *          deserialization.
 473      * @throws  StreamCorruptedException Control information in the
 474      *          stream is inconsistent.
 475      * @throws  OptionalDataException Primitive data was found in the
 476      *          stream instead of objects.
 477      * @throws  IOException Any of the usual Input/Output related exceptions.
 478      */
 479     public final Object readObject()
 480         throws IOException, ClassNotFoundException {
 481         return readObject(Object.class);
 482     }
 483 

2151      * class is unresolvable (in which case a ClassNotFoundException will be
2152      * associated with object's handle).  Sets passHandle to object's assigned
2153      * handle.
2154      */
2155     private Object readOrdinaryObject(boolean unshared)
2156         throws IOException
2157     {
2158         if (bin.readByte() != TC_OBJECT) {
2159             throw new InternalError();
2160         }
2161 
2162         ObjectStreamClass desc = readClassDesc(false);
2163         desc.checkDeserialize();
2164 
2165         Class<?> cl = desc.forClass();
2166         if (cl == String.class || cl == Class.class
2167                 || cl == ObjectStreamClass.class) {
2168             throw new InvalidClassException("invalid class descriptor");
2169         }
2170 
2171         // Assign the handle and initially set to null or the unsharedMarker
2172         passHandle = handles.assign(unshared ? unsharedMarker : null);







2173         ClassNotFoundException resolveEx = desc.getResolveException();
2174         if (resolveEx != null) {
2175             handles.markException(passHandle, resolveEx);
2176         }
2177 
2178         try {
2179             // Dispatch on the factory mode to read an object from the stream.
2180             Object obj = switch (desc.factoryMode()) {
2181                 case READ_OBJECT_DEFAULT -> readSerialDefaultObject(desc, unshared);
2182                 case READ_OBJECT_CUSTOM -> readSerialCustomData(desc, unshared);
2183                 case READ_RECORD -> readRecord(desc, unshared);
2184                 case READ_EXTERNALIZABLE -> readExternalObject(desc, unshared);
2185                 case READ_OBJECT_VALUE -> readObjectValue(desc, unshared);
2186                 case READ_NO_LOCAL_CLASS -> readAbsentLocalClass(desc, unshared);
2187                 case null -> throw new AssertionError("Unknown factoryMode for: " + desc.getName(),
2188                         resolveEx);
2189             };
2190 
2191             handles.finish(passHandle);
2192 
2193             if (obj != null &&
2194                 handles.lookupException(passHandle) == null &&
2195                 desc.hasReadResolveMethod())
2196             {
2197                 Object rep = desc.invokeReadResolve(obj);
2198                 if (unshared && rep.getClass().isArray()) {
2199                     rep = cloneArray(rep);
2200                 }
2201                 if (rep != obj) {
2202                     // Filter the replacement object
2203                     if (rep != null) {
2204                         if (rep.getClass().isArray()) {
2205                             filterCheck(rep.getClass(), Array.getLength(rep));
2206                         } else {
2207                             filterCheck(rep.getClass(), -1);
2208                         }
2209                     }
2210                     handles.setObject(passHandle, obj = rep);
2211                 }

2212             }
2213 
2214             return obj;
2215         } catch (UncheckedIOException uioe) {
2216             // Consistent re-throw for nested UncheckedIOExceptions
2217             throw uioe.getCause();
2218         }
2219     }
2220 
2221     /**
2222      * {@return a value class instance by invoking its constructor with field values read from the stream.
2223      * The fields of the class in the stream are matched to the local fields and applied to
2224      * the constructor.
2225      * If the stream contains superclasses with serializable fields,
2226      * an InvalidClassException is thrown with an incompatible class change message.
2227      *
2228      * @param desc the class descriptor read from the stream, the local class is a value class
2229      * @param unshared if the object is not to be shared
2230      * @throws InvalidClassException if the stream contains a superclass with serializable fields.
2231      * @throws IOException if there are I/O errors while reading from the
2232      *         underlying {@code InputStream}
2233      */
2234     private Object readObjectValue(ObjectStreamClass desc, boolean unshared) throws IOException {
2235         final ObjectStreamClass localDesc = desc.getLocalDesc();
2236         TRACE("readObjectValue: %s, local class: %s", desc.getName(), localDesc.getName());
2237         // Check for un-expected fields in superclasses
2238         List<ClassDataSlot> slots = desc.getClassDataLayout();
2239         for (int i = 0; i < slots.size()-1; i++) {
2240             ClassDataSlot slot = slots.get(i);
2241             if (slot.hasData && slot.desc.getFields(false).length > 0) {
2242                 throw new InvalidClassException("incompatible class change to value class: " +
2243                         "stream class has non-empty super type: " + desc.getName());
2244             }
2245         }
2246         // Read values for the value class fields
2247         FieldValues fieldValues = new FieldValues(desc, true);
2248 
2249         // Get value object constructor adapted to take primitive value buffer and object array.
2250         MethodHandle consMH = ConstructorSupport.deserializationValueCons(desc);
2251         try {
2252             Object obj = (Object) consMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2253             if (!unshared)
2254                 handles.setObject(passHandle, obj);
2255             return obj;
2256         } catch (Exception e) {
2257             throw new InvalidObjectException(e.getMessage(), e);
2258         } catch (Error e) {
2259             throw e;
2260         } catch (Throwable t) {
2261             throw new InvalidObjectException("ReflectiveOperationException " +
2262                     "during deserialization", t);
2263         }
2264     }
2265 
2266     /**
2267      * Creates a new object and invokes its readExternal method to read its contents.
2268      *
2269      * If the class is instantiable, read externalizable data by invoking readExternal()
2270      * method of obj; otherwise, attempts to skip over externalizable data.
2271      * Expects that passHandle is set to obj's handle before this method is
2272      * called.  The new object is entered in the handle table immediately,
2273      * allowing it to leak before it is completely read.
2274      */
2275     private Object readExternalObject(ObjectStreamClass desc, boolean unshared)
2276         throws IOException
2277     {
2278         TRACE("readExternalObject: %s", desc.getName());
2279 
2280         // For Externalizable objects,
2281         // create the instance, publish the ref, and read the data
2282         Externalizable obj = null;
2283         try {
2284             if (desc.isInstantiable()) {
2285                 obj = (Externalizable) desc.newInstance();
2286             }
2287         } catch (Exception ex) {
2288             throw new InvalidClassException(desc.getName(),
2289                     "unable to create instance", ex);
2290         }
2291 
2292         if (!unshared)
2293             handles.setObject(passHandle, obj);
2294 
2295         SerialCallbackContext oldContext = curContext;
2296         if (oldContext != null)
2297             oldContext.check();
2298         curContext = null;
2299         try {
2300             boolean blocked = desc.hasBlockExternalData();
2301             if (blocked) {
2302                 bin.setBlockDataMode(true);
2303             }
2304             if (obj != null) {
2305                 try {
2306                     obj.readExternal(this);
2307                 } catch (ClassNotFoundException ex) {
2308                     /*
2309                      * In most cases, the handle table has already propagated
2310                      * a CNFException to passHandle at this point; this mark
2311                      * call is included to address cases where the readExternal
2312                      * method has cons'ed and thrown a new CNFException of its
2313                      * own.
2314                      */

2318             if (blocked) {
2319                 skipCustomData();
2320             }
2321         } finally {
2322             if (oldContext != null)
2323                 oldContext.check();
2324             curContext = oldContext;
2325         }
2326         /*
2327          * At this point, if the externalizable data was not written in
2328          * block-data form and either the externalizable class doesn't exist
2329          * locally (i.e., obj == null) or readExternal() just threw a
2330          * CNFException, then the stream is probably in an inconsistent state,
2331          * since some (or all) of the externalizable data may not have been
2332          * consumed.  Since there's no "correct" action to take in this case,
2333          * we mimic the behavior of past serialization implementations and
2334          * blindly hope that the stream is in sync; if it isn't and additional
2335          * externalizable data remains in the stream, a subsequent read will
2336          * most likely throw a StreamCorruptedException.
2337          */
2338         return obj;
2339     }
2340 
2341     /**
2342      * Reads and returns a record.
2343      * If an exception is marked for any of the fields, the dependency
2344      * mechanism marks the record as having an exception.
2345      * Null is returned from readRecord and later the exception is thrown at
2346      * the exit of {@link #readObject(Class)}.
2347      */
2348     private Object readRecord(ObjectStreamClass desc, boolean unshared) throws IOException {
2349         TRACE("invoking readRecord: %s", desc.getName());
2350         List<ClassDataSlot> slots = desc.getClassDataLayout();
2351         if (slots.size() != 1) {
2352             // skip any superclass stream field values
2353             for (int i = 0; i < slots.size()-1; i++) {
2354                 if (slots.get(i).hasData) {
2355                     new FieldValues(slots.get(i).desc, true);
2356                 }
2357             }
2358         }
2359 
2360         FieldValues fieldValues = new FieldValues(desc, true);
2361         if (handles.lookupException(passHandle) != null) {
2362             return null;     // slot marked with exception, don't create record
2363         }
2364 
2365         // get canonical record constructor adapted to take two arguments:
2366         // - byte[] primValues
2367         // - Object[] objValues
2368         // and return Object
2369         MethodHandle ctrMH = ConstructorSupport.deserializationCtr(desc);
2370 
2371         try {
2372             Object obj = (Object) ctrMH.invokeExact(fieldValues.primValues, fieldValues.objValues);
2373             if (!unshared)
2374                 handles.setObject(passHandle, obj);
2375             return obj;
2376         } catch (Exception e) {
2377             throw new InvalidObjectException(e.getMessage(), e);
2378         } catch (Error e) {
2379             throw e;
2380         } catch (Throwable t) {
2381             throw new InvalidObjectException("ReflectiveOperationException " +
2382                                              "during deserialization", t);
2383         }
2384     }
2385 
2386     /**
2387      * Construct an object from the stream for a class that has only default read object behaviors.
2388      * For each object, the fields are read before any are assigned.
2389      * The new instance is entered in the handle table if it is unshared,
2390      * allowing it to escape before it is initialized.
2391      * The `readObject` and `readObjectNoData` methods are not present and are not called.
2392      *
2393      * @param desc the class descriptor
2394      * @param unshared true if the object should be shared
2395      * @return the object constructed from the stream data
2396      * @throws IOException if there are I/O errors while reading from the
2397      *         underlying {@code InputStream}
2398      * @throws InvalidClassException if the instance creation fails
2399      */
2400     private Object readSerialDefaultObject(ObjectStreamClass desc, boolean unshared)
2401             throws IOException, InvalidClassException {
2402         if (!desc.isInstantiable()) {
2403             // No local class to create, read and discard
2404             return readAbsentLocalClass(desc, unshared);
2405         }
2406         TRACE("readSerialDefaultObject: %s", desc.getName());
2407         try {
2408             final Object obj = desc.newInstance();
2409             if (!unshared)
2410                 handles.setObject(passHandle, obj);
2411 
2412             // Best effort Failure Atomicity; slotValues will be non-null if field
2413             // values can be set after reading all field data in the hierarchy.
2414             List<FieldValues> slotValues = desc.getClassDataLayout().stream()
2415                     .filter(s -> s.hasData)
2416                     .map(s1 -> {
2417                         var values = new FieldValues(s1.desc, true);
2418                         finishBlockData(s1.desc);
2419                         return values;
2420                     })
2421                     .toList();
2422 
2423             if (handles.lookupException(passHandle) != null) {
2424                 return null;    // some exception for a class, do not return the object
2425             }
2426 
2427             // Check that the types are assignable for all slots before assigning.
2428             slotValues.forEach(v -> v.defaultCheckFieldValues(obj));
2429             slotValues.forEach(v -> v.defaultSetFieldValues(obj));
2430             return obj;
2431         } catch (InstantiationException | InvocationTargetException ex) {
2432             throw new InvalidClassException(desc.forClass().getName(),
2433                     "unable to create instance", ex);
2434         }
2435     }
2436 
2437 
2438     /**
2439      * Reads (or attempts to skip, if not instantiatable or is tagged with a
2440      * ClassNotFoundException) instance data for each serializable class of
2441      * object in stream, from superclass to subclass.
2442      * Expects that passHandle is set to current handle before this method is called.
2443      */
2444     private Object readSerialCustomData(ObjectStreamClass desc, boolean unshared)
2445         throws IOException
2446     {
2447         if (!desc.isInstantiable()) {
2448             // No local class to create, read and discard
2449             return readAbsentLocalClass(desc, unshared);













2450         }






2451 
2452         TRACE("readSerialCustomData: %s, ex: %s", desc.getName(), handles.lookupException(passHandle));
2453         try {
2454             Object obj = desc.newInstance();
2455             if (!unshared)
2456                 handles.setObject(passHandle, obj);
2457             // Read data into each of the slots for the class
2458             return readSerialCustomSlots(obj, desc.getClassDataLayout());
2459         } catch (InstantiationException | InvocationTargetException ex) {
2460             throw new InvalidClassException(desc.forClass().getName(),
2461                     "unable to create instance", ex);
2462         }
2463     }
















2464 
2465     /**
2466      * Reads from the stream using custom or default readObject methods appropriate.
2467      * For each slot, either the custom readObject method or the default reader of fields
2468      * is invoked. Unused slot specific custom data is discarded.
2469      * This function is used by {@link #readSerialCustomData}.
2470      *
2471      * @param obj the object to assign the values to
2472      * @param slots a list of slots to read from the stream
2473      * @return the object being initialized
2474      * @throws IOException if there are I/O errors while reading from the
2475      *         underlying {@code InputStream}
2476      */
2477     private Object readSerialCustomSlots(Object obj, List<ClassDataSlot> slots) throws IOException {
2478         TRACE("    readSerialCustomSlots: %s", slots);
2479 
2480         for (ClassDataSlot slot : slots) {
2481             ObjectStreamClass slotDesc = slot.desc;
2482             if (slot.hasData) {
2483                 if (slotDesc.hasReadObjectMethod() &&
2484                         handles.lookupException(passHandle) == null) {
2485                     // Invoke slot custom readObject method
2486                     readSlotViaReadObject(obj, slotDesc);
2487                 } else {
2488                     // Read fields of the current descriptor into a new FieldValues
2489                     FieldValues values = new FieldValues(slotDesc, true);
2490                     if (handles.lookupException(passHandle) == null) {
2491                         // Set the instance fields if no previous exception
2492                         values.defaultCheckFieldValues(obj);
2493                         values.defaultSetFieldValues(obj);




2494                     }
2495                     finishBlockData(slotDesc);





2496                 }
2497             } else {
2498                 if (slotDesc.hasReadObjectNoDataMethod() &&
2499                         handles.lookupException(passHandle) == null) {


2500                     slotDesc.invokeReadObjectNoData(obj);
2501                 }
2502             }
2503         }
2504         return obj;
2505     }
2506 
2507     /**
2508      * Invoke the readObject method of the class to read and store the state from the stream.
2509      *
2510      * @param obj an instance of the class being created, only partially initialized.
2511      * @param slotDesc the ObjectStreamDescriptor for the current class
2512      * @throws IOException if there are I/O errors while reading from the
2513      *         underlying {@code InputStream}
2514      */
2515     private void readSlotViaReadObject(Object obj, ObjectStreamClass slotDesc) throws IOException {
2516         TRACE("readSlotViaReadObject: %s", slotDesc.getName());
2517         assert obj != null : "readSlotViaReadObject called when obj == null";
2518 
2519         SerialCallbackContext oldContext = curContext;
2520         if (oldContext != null)
2521             oldContext.check();
2522         try {
2523             curContext = new SerialCallbackContext(obj, slotDesc);
2524 
2525             bin.setBlockDataMode(true);
2526             slotDesc.invokeReadObject(obj, this);
2527         } catch (ClassNotFoundException ex) {
2528             /*
2529              * In most cases, the handle table has already
2530              * propagated a CNFException to passHandle at this
2531              * point; this mark call is included to address cases
2532              * where the custom readObject method has cons'ed and
2533              * thrown a new CNFException of its own.
2534              */
2535             handles.markException(passHandle, ex);
2536         } finally {
2537             curContext.setUsed();
2538             if (oldContext!= null)
2539                 oldContext.check();
2540             curContext = oldContext;
2541         }
2542 
2543         /*
2544          * defaultDataEnd may have been set indirectly by custom
2545          * readObject() method when calling defaultReadObject() or
2546          * readFields(); clear it to restore normal read behavior.
2547          */
2548         defaultDataEnd = false;
2549 
2550         finishBlockData(slotDesc);
2551     }
2552 
2553 
2554     /**
2555      * Read and discard an entire object, leaving a null reference in the HandleTable.
2556      * The descriptor of the class in the stream is used to read the fields from the stream.
2557      * There is no instance in which to store the field values.
2558      * Custom data following the fields of any slot is read and discarded.
2559      * References to nested objects are read and retained in the
2560      * handle table using the regular mechanism.
2561      * Handles later in the stream may refer to the nested objects.
2562      *
2563      * @param desc the stream class descriptor
2564      * @param unshared the unshared flag, ignored since no object is created
2565      * @return null, no object is created
2566      * @throws IOException if there are I/O errors while reading from the
2567      *         underlying {@code InputStream}
2568      */
2569     private Object readAbsentLocalClass(ObjectStreamClass desc, boolean unshared)
2570             throws IOException {
2571         TRACE("readAbsentLocalClass: %s", desc.getName());
2572         desc.getClassDataLayout().stream()
2573                 .filter(s -> s.hasData)
2574                 .forEach(s2 -> {new FieldValues(s2.desc, true); finishBlockData(s2.desc);});
2575         return null;
2576     }
2577 
2578     // Finish handling of block data by skipping any remaining and setting BlockDataMode = false
2579     private void finishBlockData(ObjectStreamClass slotDesc) throws UncheckedIOException {
2580         try {
2581             if (slotDesc.hasWriteObjectData()) {
2582                 skipCustomData();
2583             } else {
2584                 bin.setBlockDataMode(false);
2585             }
2586         } catch (IOException ioe) {
2587             throw new UncheckedIOException(ioe);
2588         }
2589     }
2590 
2591     /**
2592      * Skips over all block data and objects until TC_ENDBLOCKDATA is
2593      * encountered.
2594      */
2595     private void skipCustomData() throws IOException {
2596         int oldHandle = passHandle;
2597         for (;;) {
2598             if (bin.getBlockDataMode()) {
2599                 bin.skipBlockData();
2600                 bin.setBlockDataMode(false);
2601             }
2602             switch (bin.peekByte()) {
2603                 case TC_BLOCKDATA:
2604                 case TC_BLOCKDATALONG:
2605                     bin.setBlockDataMode(true);
2606                     break;
2607 

2663     /**
2664      * Default GetField implementation.
2665      */
2666     private final class FieldValues extends GetField {
2667 
2668         /** class descriptor describing serializable fields */
2669         private final ObjectStreamClass desc;
2670         /** primitive field values */
2671         final byte[] primValues;
2672         /** object field values */
2673         final Object[] objValues;
2674         /** object field value handles */
2675         private final int[] objHandles;
2676 
2677         /**
2678          * Creates FieldValues object for reading fields defined in given
2679          * class descriptor.
2680          * @param desc the ObjectStreamClass to read
2681          * @param recordDependencies if true, record the dependencies
2682          *                           from current PassHandle and the object's read.
2683          * @throws UncheckedIOException if any IOException occurs
2684          */
2685         FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws UncheckedIOException {
2686             try {
2687                 this.desc = desc;
2688                 TRACE("    reading FieldValues: %s", desc.getName());
2689                 int primDataSize = desc.getPrimDataSize();
2690                 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2691                 if (primDataSize > 0) {
2692                     bin.readFully(primValues, 0, primDataSize, false);
2693                 }
2694 





2695 
2696                 int numObjFields = desc.getNumObjFields();
2697                 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2698                 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2699                 if (numObjFields > 0) {
2700                     int objHandle = passHandle;
2701                     ObjectStreamField[] fields = desc.getFields(false);
2702                     int numPrimFields = fields.length - objValues.length;
2703                     for (int i = 0; i < objValues.length; i++) {
2704                         ObjectStreamField f = fields[numPrimFields + i];
2705                         objValues[i] = readObject0(Object.class, f.isUnshared());
2706                         objHandles[i] = passHandle;
2707                         if (recordDependencies && f.getField() != null) {
2708                             handles.markDependency(objHandle, passHandle);
2709                         }
2710                     }
2711                     passHandle = objHandle;
2712                 }
2713             } catch (IOException ioe) {
2714                 throw new UncheckedIOException(ioe);
2715             }
2716         }
2717 
2718         public ObjectStreamClass getObjectStreamClass() {
2719             return desc;
2720         }
2721 
2722         public boolean defaulted(String name) {
2723             return (getFieldOffset(name, null) < 0);
2724         }
2725 
2726         public boolean get(String name, boolean val) {
2727             int off = getFieldOffset(name, Boolean.TYPE);
2728             return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2729         }
2730 
2731         public byte get(String name, byte val) {
2732             int off = getFieldOffset(name, Byte.TYPE);
2733             return (off >= 0) ? primValues[off] : val;
2734         }
< prev index next >