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 }
|