< 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 
 259         /**
 260          * Property to permit setting a filter after objects
 261          * have been read.
 262          * See {@link #setObjectInputFilter(ObjectInputFilter)}
 263          */
 264         static final boolean SET_FILTER_AFTER_READ =
 265                 Boolean.getBoolean("jdk.serialSetFilterAfterRead");
 266 
 267         /**
 268          * Property to control {@link GetField#get(String, Object)} conversion of
 269          * {@link ClassNotFoundException} to {@code null}. If set to {@code true}
 270          * {@link GetField#get(String, Object)} returns null otherwise

 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         }

   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 
 279         /**
 280          * Property to permit setting a filter after objects
 281          * have been read.
 282          * See {@link #setObjectInputFilter(ObjectInputFilter)}
 283          */
 284         static final boolean SET_FILTER_AFTER_READ =
 285                 Boolean.getBoolean("jdk.serialSetFilterAfterRead");
 286 
 287         /**
 288          * Property to control {@link GetField#get(String, Object)} conversion of
 289          * {@link ClassNotFoundException} to {@code null}. If set to {@code true}
 290          * {@link GetField#get(String, Object)} returns null otherwise

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

2118      * class is unresolvable (in which case a ClassNotFoundException will be
2119      * associated with object's handle).  Sets passHandle to object's assigned
2120      * handle.
2121      */
2122     private Object readOrdinaryObject(boolean unshared)
2123         throws IOException
2124     {
2125         if (bin.readByte() != TC_OBJECT) {
2126             throw new InternalError();
2127         }
2128 
2129         ObjectStreamClass desc = readClassDesc(false);
2130         desc.checkDeserialize();
2131 
2132         Class<?> cl = desc.forClass();
2133         if (cl == String.class || cl == Class.class
2134                 || cl == ObjectStreamClass.class) {
2135             throw new InvalidClassException("invalid class descriptor");
2136         }
2137 
2138         // Assign the handle and initially set to null or the unsharedMarker
2139         passHandle = handles.assign(unshared ? unsharedMarker : null);







2140         ClassNotFoundException resolveEx = desc.getResolveException();
2141         if (resolveEx != null) {
2142             handles.markException(passHandle, resolveEx);
2143         }
2144 
2145         try {
2146             // Dispatch on the factory mode to read an object from the stream.
2147             Object obj = switch (desc.factoryMode()) {
2148                 case READ_OBJECT_DEFAULT -> readSerialDefaultObject(desc, unshared);
2149                 case READ_OBJECT_CUSTOM -> readSerialCustomData(desc, unshared);
2150                 case READ_RECORD -> readRecord(desc, unshared);
2151                 case READ_EXTERNALIZABLE -> readExternalObject(desc, unshared);
2152                 case READ_OBJECT_VALUE -> readObjectValue(desc, unshared);
2153                 case READ_NO_LOCAL_CLASS -> readAbsentLocalClass(desc, unshared);
2154                 case null -> throw new AssertionError("Unknown factoryMode for: " + desc.getName(),
2155                         resolveEx);
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
2170                     if (rep != null) {
2171                         if (rep.getClass().isArray()) {
2172                             filterCheck(rep.getClass(), Array.getLength(rep));
2173                         } else {
2174                             filterCheck(rep.getClass(), -1);
2175                         }
2176                     }
2177                     handles.setObject(passHandle, obj = rep);
2178                 }

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

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













2417         }






2418 
2419         TRACE("readSerialCustomData: %s, ex: %s", desc.getName(), handles.lookupException(passHandle));
2420         try {
2421             Object obj = desc.newInstance();
2422             if (!unshared)
2423                 handles.setObject(passHandle, obj);
2424             // Read data into each of the slots for the class
2425             return readSerialCustomSlots(obj, desc.getClassDataLayout());
2426         } catch (InstantiationException | InvocationTargetException ex) {
2427             throw new InvalidClassException(desc.forClass().getName(),
2428                     "unable to create instance", ex);
2429         }
2430     }
















2431 
2432     /**
2433      * Reads from the stream using custom or default readObject methods appropriate.
2434      * For each slot, either the custom readObject method or the default reader of fields
2435      * is invoked. Unused slot specific custom data is discarded.
2436      * This function is used by {@link #readSerialCustomData}.
2437      *
2438      * @param obj the object to assign the values to
2439      * @param slots a list of slots to read from the stream
2440      * @return the object being initialized
2441      * @throws IOException if there are I/O errors while reading from the
2442      *         underlying {@code InputStream}
2443      */
2444     private Object readSerialCustomSlots(Object obj, List<ClassDataSlot> slots) throws IOException {
2445         TRACE("    readSerialCustomSlots: %s", slots);
2446 
2447         for (ClassDataSlot slot : slots) {
2448             ObjectStreamClass slotDesc = slot.desc;
2449             if (slot.hasData) {
2450                 if (slotDesc.hasReadObjectMethod() &&
2451                         handles.lookupException(passHandle) == null) {
2452                     // Invoke slot custom readObject method
2453                     readSlotViaReadObject(obj, slotDesc);
2454                 } else {
2455                     // Read fields of the current descriptor into a new FieldValues
2456                     FieldValues values = new FieldValues(slotDesc, true);
2457                     if (handles.lookupException(passHandle) == null) {
2458                         // Set the instance fields if no previous exception
2459                         values.defaultCheckFieldValues(obj);
2460                         values.defaultSetFieldValues(obj);




2461                     }
2462                     finishBlockData(slotDesc);





2463                 }
2464             } else {
2465                 if (slotDesc.hasReadObjectNoDataMethod() &&
2466                         handles.lookupException(passHandle) == null) {


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

2630     /**
2631      * Default GetField implementation.
2632      */
2633     private final class FieldValues extends GetField {
2634 
2635         /** class descriptor describing serializable fields */
2636         private final ObjectStreamClass desc;
2637         /** primitive field values */
2638         final byte[] primValues;
2639         /** object field values */
2640         final Object[] objValues;
2641         /** object field value handles */
2642         private final int[] objHandles;
2643 
2644         /**
2645          * Creates FieldValues object for reading fields defined in given
2646          * class descriptor.
2647          * @param desc the ObjectStreamClass to read
2648          * @param recordDependencies if true, record the dependencies
2649          *                           from current PassHandle and the object's read.
2650          * @throws UncheckedIOException if any IOException occurs
2651          */
2652         FieldValues(ObjectStreamClass desc, boolean recordDependencies) throws UncheckedIOException {
2653             try {
2654                 this.desc = desc;
2655                 TRACE("    reading FieldValues: %s", desc.getName());
2656                 int primDataSize = desc.getPrimDataSize();
2657                 primValues = (primDataSize > 0) ? new byte[primDataSize] : null;
2658                 if (primDataSize > 0) {
2659                     bin.readFully(primValues, 0, primDataSize, false);
2660                 }
2661 





2662 
2663                 int numObjFields = desc.getNumObjFields();
2664                 objValues = (numObjFields > 0) ? new Object[numObjFields] : null;
2665                 objHandles = (numObjFields > 0) ? new int[numObjFields] : null;
2666                 if (numObjFields > 0) {
2667                     int objHandle = passHandle;
2668                     ObjectStreamField[] fields = desc.getFields(false);
2669                     int numPrimFields = fields.length - objValues.length;
2670                     for (int i = 0; i < objValues.length; i++) {
2671                         ObjectStreamField f = fields[numPrimFields + i];
2672                         objValues[i] = readObject0(Object.class, f.isUnshared());
2673                         objHandles[i] = passHandle;
2674                         if (recordDependencies && f.getField() != null) {
2675                             handles.markDependency(objHandle, passHandle);
2676                         }
2677                     }
2678                     passHandle = objHandle;
2679                 }
2680             } catch (IOException ioe) {
2681                 throw new UncheckedIOException(ioe);
2682             }
2683         }
2684 
2685         public ObjectStreamClass getObjectStreamClass() {
2686             return desc;
2687         }
2688 
2689         public boolean defaulted(String name) {
2690             return (getFieldOffset(name, null) < 0);
2691         }
2692 
2693         public boolean get(String name, boolean val) {
2694             int off = getFieldOffset(name, Boolean.TYPE);
2695             return (off >= 0) ? ByteArray.getBoolean(primValues, off) : val;
2696         }
2697 
2698         public byte get(String name, byte val) {
2699             int off = getFieldOffset(name, Byte.TYPE);
2700             return (off >= 0) ? primValues[off] : val;
2701         }
< prev index next >