< prev index next >

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

Print this page

  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.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.reflect.Constructor;
  32 import java.lang.reflect.Field;

  33 import java.lang.reflect.InvocationTargetException;
  34 import java.lang.reflect.RecordComponent;
  35 import java.lang.reflect.UndeclaredThrowableException;
  36 import java.lang.reflect.Member;
  37 import java.lang.reflect.Method;
  38 import java.lang.reflect.Modifier;
  39 import java.lang.reflect.Proxy;
  40 import java.security.AccessControlContext;
  41 import java.security.AccessController;
  42 import java.security.MessageDigest;
  43 import java.security.NoSuchAlgorithmException;
  44 import java.security.PermissionCollection;
  45 import java.security.Permissions;
  46 import java.security.PrivilegedAction;
  47 import java.security.PrivilegedActionException;
  48 import java.security.PrivilegedExceptionAction;
  49 import java.security.ProtectionDomain;
  50 import java.util.ArrayList;
  51 import java.util.Arrays;
  52 import java.util.Collections;

  54 import java.util.HashSet;
  55 import java.util.Map;
  56 import java.util.Set;
  57 import java.util.concurrent.ConcurrentHashMap;
  58 import jdk.internal.misc.Unsafe;
  59 import jdk.internal.reflect.CallerSensitive;
  60 import jdk.internal.reflect.Reflection;
  61 import jdk.internal.reflect.ReflectionFactory;
  62 import jdk.internal.access.SharedSecrets;
  63 import jdk.internal.access.JavaSecurityAccess;
  64 import jdk.internal.util.ByteArray;
  65 import sun.reflect.misc.ReflectUtil;
  66 
  67 /**
  68  * Serialization's descriptor for classes.  It contains the name and
  69  * serialVersionUID of the class.  The ObjectStreamClass for a specific class
  70  * loaded in this Java VM can be found/created using the lookup method.
  71  *
  72  * <p>The algorithm to compute the SerialVersionUID is described in
  73  * <a href="{@docRoot}/../specs/serialization/class.html#stream-unique-identifiers">
  74  *    <cite>Java Object Serialization Specification,</cite> Section 4.6, "Stream Unique Identifiers"</a>.
  75  *
  76  * @spec serialization/index.html Java Object Serialization Specification
  77  * @author      Mike Warres
  78  * @author      Roger Riggs
  79  * @see ObjectStreamField
  80  * @see <a href="{@docRoot}/../specs/serialization/class.html">
  81  *      <cite>Java Object Serialization Specification,</cite> Section 4, "Class Descriptors"</a>
  82  * @since   1.1
  83  */
  84 public final class ObjectStreamClass implements Serializable {
  85 
  86     /** serialPersistentFields value indicating no serializable fields */
  87     public static final ObjectStreamField[] NO_FIELDS =
  88         new ObjectStreamField[0];
  89 
  90     @java.io.Serial
  91     private static final long serialVersionUID = -6120832682080437368L;
  92     /**
  93      * {@code ObjectStreamClass} has no fields for default serialization.
  94      */

 118                 @Override
 119                 protected Map<FieldReflectorKey, FieldReflector> computeValue(Class<?> type) {
 120                     return new ConcurrentHashMap<>();
 121                 }
 122             };
 123     }
 124 
 125     /** class associated with this descriptor (if any) */
 126     private Class<?> cl;
 127     /** name of class represented by this descriptor */
 128     private String name;
 129     /** serialVersionUID of represented class (null if not computed yet) */
 130     private volatile Long suid;
 131 
 132     /** true if represents dynamic proxy class */
 133     private boolean isProxy;
 134     /** true if represents enum type */
 135     private boolean isEnum;
 136     /** true if represents record type */
 137     private boolean isRecord;


 138     /** true if represented class implements Serializable */
 139     private boolean serializable;
 140     /** true if represented class implements Externalizable */
 141     private boolean externalizable;
 142     /** true if desc has data written by class-defined writeObject method */
 143     private boolean hasWriteObjectData;
 144     /**
 145      * true if desc has externalizable data written in block data format; this
 146      * must be true by default to accommodate ObjectInputStream subclasses which
 147      * override readClassDescriptor() to return class descriptors obtained from
 148      * ObjectStreamClass.lookup() (see 4461737)
 149      */
 150     private boolean hasBlockExternalData = true;
 151 
 152     /**
 153      * Contains information about InvalidClassException instances to be thrown
 154      * when attempting operations on an invalid class. Note that instances of
 155      * this class are immutable and are potentially shared among
 156      * ObjectStreamClass instances.
 157      */

 357      * @param   all if true, return descriptors for all classes; if false, only
 358      *          return descriptors for serializable classes
 359      */
 360     static ObjectStreamClass lookup(Class<?> cl, boolean all) {
 361         if (!(all || Serializable.class.isAssignableFrom(cl))) {
 362             return null;
 363         }
 364         return Caches.localDescs.get(cl);
 365     }
 366 
 367     /**
 368      * Creates local class descriptor representing given class.
 369      */
 370     @SuppressWarnings("removal")
 371     private ObjectStreamClass(final Class<?> cl) {
 372         this.cl = cl;
 373         name = cl.getName();
 374         isProxy = Proxy.isProxyClass(cl);
 375         isEnum = Enum.class.isAssignableFrom(cl);
 376         isRecord = cl.isRecord();

 377         serializable = Serializable.class.isAssignableFrom(cl);
 378         externalizable = Externalizable.class.isAssignableFrom(cl);
 379 
 380         Class<?> superCl = cl.getSuperclass();
 381         superDesc = (superCl != null) ? lookup(superCl, false) : null;
 382         localDesc = this;
 383 
 384         if (serializable) {
 385             AccessController.doPrivileged(new PrivilegedAction<>() {
 386                 public Void run() {
 387                     if (isEnum) {
 388                         suid = 0L;
 389                         fields = NO_FIELDS;
 390                         return null;
 391                     }
 392                     if (cl.isArray()) {
 393                         fields = NO_FIELDS;
 394                         return null;
 395                     }
 396 
 397                     suid = getDeclaredSUID(cl);
 398                     try {
 399                         fields = getSerialFields(cl);
 400                         computeFieldOffsets();
 401                     } catch (InvalidClassException e) {
 402                         serializeEx = deserializeEx =
 403                             new ExceptionInfo(e.classname, e.getMessage());
 404                         fields = NO_FIELDS;
 405                     }
 406 
 407                     if (isRecord) {
 408                         canonicalCtr = canonicalRecordCtr(cl);
 409                         deserializationCtrs = new DeserializationConstructorsCache();



 410                     } else if (externalizable) {
 411                         cons = getExternalizableConstructor(cl);
 412                     } else {
 413                         cons = getSerializableConstructor(cl);
 414                         writeObjectMethod = getPrivateMethod(cl, "writeObject",
 415                             new Class<?>[] { ObjectOutputStream.class },
 416                             Void.TYPE);
 417                         readObjectMethod = getPrivateMethod(cl, "readObject",
 418                             new Class<?>[] { ObjectInputStream.class },
 419                             Void.TYPE);
 420                         readObjectNoDataMethod = getPrivateMethod(
 421                             cl, "readObjectNoData", null, Void.TYPE);
 422                         hasWriteObjectData = (writeObjectMethod != null);
 423                     }
 424                     domains = getProtectionDomains(cons, cl);
 425                     writeReplaceMethod = getInheritableMethod(
 426                         cl, "writeReplace", null, Object.class);
 427                     readResolveMethod = getInheritableMethod(
 428                         cl, "readResolve", null, Object.class);
 429                     return null;
 430                 }
 431             });
 432         } else {
 433             suid = 0L;
 434             fields = NO_FIELDS;
 435         }
 436 
 437         try {
 438             fieldRefl = getReflector(fields, this);
 439         } catch (InvalidClassException ex) {
 440             // field mismatches impossible when matching local fields vs. self
 441             throw new InternalError(ex);
 442         }
 443 
 444         if (deserializeEx == null) {
 445             if (isEnum) {
 446                 deserializeEx = new ExceptionInfo(name, "enum type");
 447             } else if (cons == null && !isRecord) {
 448                 deserializeEx = new ExceptionInfo(name, "no valid constructor");
 449             }
 450         }
 451         if (isRecord && canonicalCtr == null) {
 452             deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
 453         } else {
 454             for (int i = 0; i < fields.length; i++) {
 455                 if (fields[i].getField() == null) {
 456                     defaultSerializeEx = new ExceptionInfo(
 457                         name, "unmatched serializable field(s) declared");
 458                 }
 459             }
 460         }
 461         initialized = true;
 462     }
 463 
 464     /**
 465      * Creates blank class descriptor which should be initialized via a
 466      * subsequent call to initProxy(), initNonProxy() or readNonProxy().
 467      */

 621         }
 622 
 623         this.cl = cl;
 624         this.resolveEx = resolveEx;
 625         this.superDesc = superDesc;
 626         name = model.name;
 627         this.suid = suid;
 628         isProxy = false;
 629         isEnum = model.isEnum;
 630         serializable = model.serializable;
 631         externalizable = model.externalizable;
 632         hasBlockExternalData = model.hasBlockExternalData;
 633         hasWriteObjectData = model.hasWriteObjectData;
 634         fields = model.fields;
 635         primDataSize = model.primDataSize;
 636         numObjFields = model.numObjFields;
 637 
 638         if (osc != null) {
 639             localDesc = osc;
 640             isRecord = localDesc.isRecord;

 641             // canonical record constructor is shared
 642             canonicalCtr = localDesc.canonicalCtr;
 643             // cache of deserialization constructors is shared
 644             deserializationCtrs = localDesc.deserializationCtrs;
 645             writeObjectMethod = localDesc.writeObjectMethod;
 646             readObjectMethod = localDesc.readObjectMethod;
 647             readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
 648             writeReplaceMethod = localDesc.writeReplaceMethod;
 649             readResolveMethod = localDesc.readResolveMethod;
 650             if (deserializeEx == null) {
 651                 deserializeEx = localDesc.deserializeEx;
 652             }
 653             domains = localDesc.domains;
 654             assert cl.isRecord() ? localDesc.cons == null : true;
 655             cons = localDesc.cons;
 656         }
 657 
 658         fieldRefl = getReflector(fields, localDesc);
 659         // reassign to matched fields so as to reflect local unshared settings
 660         fields = fieldRefl.getFields();

 902     }
 903 
 904     /**
 905      * Returns true if represented class implements Externalizable, false
 906      * otherwise.
 907      */
 908     boolean isExternalizable() {
 909         requireInitialized();
 910         return externalizable;
 911     }
 912 
 913     /**
 914      * Returns true if represented class implements Serializable, false
 915      * otherwise.
 916      */
 917     boolean isSerializable() {
 918         requireInitialized();
 919         return serializable;
 920     }
 921 








 922     /**
 923      * Returns true if class descriptor represents externalizable class that
 924      * has written its data in 1.2 (block data) format, false otherwise.
 925      */
 926     boolean hasBlockExternalData() {
 927         requireInitialized();
 928         return hasBlockExternalData;
 929     }
 930 
 931     /**
 932      * Returns true if class descriptor represents serializable (but not
 933      * externalizable) class which has written its data via a custom
 934      * writeObject() method, false otherwise.
 935      */
 936     boolean hasWriteObjectData() {
 937         requireInitialized();
 938         return hasWriteObjectData;
 939     }
 940 
 941     /**
 942      * Returns true if represented class is serializable/externalizable and can
 943      * be instantiated by the serialization runtime--i.e., if it is
 944      * externalizable and defines a public no-arg constructor, or if it is
 945      * non-externalizable and its first non-serializable superclass defines an
 946      * accessible no-arg constructor.  Otherwise, returns false.

 947      */
 948     boolean isInstantiable() {
 949         requireInitialized();
 950         return (cons != null);
 951     }
 952 
 953     /**
 954      * Returns true if represented class is serializable (but not
 955      * externalizable) and defines a conformant writeObject method.  Otherwise,
 956      * returns false.
 957      */
 958     boolean hasWriteObjectMethod() {
 959         requireInitialized();
 960         return (writeObjectMethod != null);
 961     }
 962 
 963     /**
 964      * Returns true if represented class is serializable (but not
 965      * externalizable) and defines a conformant readObject method.  Otherwise,
 966      * returns false.
 967      */
 968     boolean hasReadObjectMethod() {
 969         requireInitialized();
 970         return (readObjectMethod != null);

1041                         if (cause instanceof IllegalAccessException iae)
1042                             throw iae;
1043                         // not supposed to happen
1044                         throw x;
1045                     }
1046                 }
1047             } catch (IllegalAccessException ex) {
1048                 // should not occur, as access checks have been suppressed
1049                 throw new InternalError(ex);
1050             } catch (InvocationTargetException ex) {
1051                 Throwable cause = ex.getCause();
1052                 if (cause instanceof Error err)
1053                     throw err;
1054                 else
1055                     throw ex;
1056             } catch (InstantiationError err) {
1057                 var ex = new InstantiationException();
1058                 ex.initCause(err);
1059                 throw ex;
1060             }
1061         } else {



1062             throw new UnsupportedOperationException();
1063         }
1064     }
1065 









1066     /**
1067      * Invokes the writeObject method of the represented serializable class.
1068      * Throws UnsupportedOperationException if this class descriptor is not
1069      * associated with a class, or if the class is externalizable,
1070      * non-serializable or does not define writeObject.
1071      */
1072     void invokeWriteObject(Object obj, ObjectOutputStream out)
1073         throws IOException, UnsupportedOperationException
1074     {
1075         requireInitialized();
1076         if (writeObjectMethod != null) {
1077             try {
1078                 writeObjectMethod.invoke(obj, new Object[]{ out });
1079             } catch (InvocationTargetException ex) {
1080                 Throwable th = ex.getCause();
1081                 if (th instanceof IOException) {
1082                     throw (IOException) th;
1083                 } else {
1084                     throwMiscException(th);
1085                 }

1420         ObjectStreamClass desc = new ObjectStreamClass();
1421         if (isProxy) {
1422             desc.initProxy(cl, null, superDesc);
1423         } else {
1424             desc.initNonProxy(this, cl, null, superDesc);
1425         }
1426         return desc;
1427     }
1428 
1429     /**
1430      * Returns public no-arg constructor of given class, or null if none found.
1431      * Access checks are disabled on the returned constructor (if any), since
1432      * the defining class may still be non-public.
1433      */
1434     private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1435         try {
1436             Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1437             cons.setAccessible(true);
1438             return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1439                 cons : null;
1440         } catch (NoSuchMethodException ex) {
1441             return null;
1442         }
1443     }
1444 
1445     /**
1446      * Returns subclass-accessible no-arg constructor of first non-serializable
1447      * superclass, or null if none found.  Access checks are disabled on the
1448      * returned constructor (if any).
1449      */
1450     private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1451         return reflFactory.newConstructorForSerialization(cl);
1452     }
1453 
1454     /**
1455      * Returns the canonical constructor for the given record class, or null if
1456      * the not found ( which should never happen for correctly generated record
1457      * classes ).
1458      */
1459     @SuppressWarnings("removal")
1460     private static MethodHandle canonicalRecordCtr(Class<?> cls) {

1913     private static final class FieldReflector {
1914 
1915         /** handle for performing unsafe operations */
1916         private static final Unsafe UNSAFE = Unsafe.getUnsafe();
1917 
1918         /** fields to operate on */
1919         private final ObjectStreamField[] fields;
1920         /** number of primitive fields */
1921         private final int numPrimFields;
1922         /** unsafe field keys for reading fields - may contain dupes */
1923         private final long[] readKeys;
1924         /** unsafe fields keys for writing fields - no dupes */
1925         private final long[] writeKeys;
1926         /** field data offsets */
1927         private final int[] offsets;
1928         /** field type codes */
1929         private final char[] typeCodes;
1930         /** field types */
1931         private final Class<?>[] types;
1932 























1933         /**
1934          * Constructs FieldReflector capable of setting/getting values from the
1935          * subset of fields whose ObjectStreamFields contain non-null
1936          * reflective Field objects.  ObjectStreamFields with null Fields are
1937          * treated as filler, for which get operations return default values
1938          * and set operations discard given values.
1939          */
1940         FieldReflector(ObjectStreamField[] fields) {
1941             this.fields = fields;
1942             int nfields = fields.length;
1943             readKeys = new long[nfields];
1944             writeKeys = new long[nfields];
1945             offsets = new int[nfields];
1946             typeCodes = new char[nfields];
1947             ArrayList<Class<?>> typeList = new ArrayList<>();
1948             Set<Long> usedKeys = new HashSet<>();
1949 
1950 
1951             for (int i = 0; i < nfields; i++) {
1952                 ObjectStreamField f = fields[i];

2033                     case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off));
2034                     default  -> throw new InternalError();
2035                 }
2036             }
2037         }
2038 
2039         /**
2040          * Fetches the serializable object field values of object obj and
2041          * stores them in array vals starting at offset 0.  The caller is
2042          * responsible for ensuring that obj is of the proper type.
2043          */
2044         void getObjFieldValues(Object obj, Object[] vals) {
2045             if (obj == null) {
2046                 throw new NullPointerException();
2047             }
2048             /* assuming checkDefaultSerialize() has been called on the class
2049              * descriptor this FieldReflector was obtained from, no field keys
2050              * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2051              */
2052             for (int i = numPrimFields; i < fields.length; i++) {

2053                 vals[offsets[i]] = switch (typeCodes[i]) {
2054                     case 'L', '[' -> UNSAFE.getReference(obj, readKeys[i]);



2055                     default       -> throw new InternalError();
2056                 };
2057             }
2058         }
2059 
2060         /**
2061          * Checks that the given values, from array vals starting at offset 0,
2062          * are assignable to the given serializable object fields.
2063          * @throws ClassCastException if any value is not assignable
2064          */
2065         void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2066             setObjFieldValues(obj, vals, true);
2067         }
2068 
2069         /**
2070          * Sets the serializable object fields of object obj using values from
2071          * array vals starting at offset 0.  The caller is responsible for
2072          * ensuring that obj is of the proper type; however, attempts to set a
2073          * field with a value of the wrong type will trigger an appropriate
2074          * ClassCastException.
2075          */
2076         void setObjFieldValues(Object obj, Object[] vals) {
2077             setObjFieldValues(obj, vals, false);
2078         }
2079 
2080         private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2081             if (obj == null) {
2082                 throw new NullPointerException();
2083             }
2084             for (int i = numPrimFields; i < fields.length; i++) {
2085                 long key = writeKeys[i];
2086                 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2087                     continue;           // discard value
2088                 }
2089                 switch (typeCodes[i]) {
2090                     case 'L', '[' -> {

2091                         Object val = vals[offsets[i]];
2092                         if (val != null &&
2093                             !types[i - numPrimFields].isInstance(val))
2094                         {
2095                             Field f = fields[i].getField();
2096                             throw new ClassCastException(
2097                                 "cannot assign instance of " +
2098                                 val.getClass().getName() + " to field " +
2099                                 f.getDeclaringClass().getName() + "." +
2100                                 f.getName() + " of type " +
2101                                 f.getType().getName() + " in instance of " +
2102                                 obj.getClass().getName());
2103                         }
2104                         if (!dryRun)
2105                             UNSAFE.putReference(obj, key, val);





2106                     }
2107                     default -> throw new InternalError();
2108                 }
2109             }
2110         }
2111     }
2112 
2113     /**
2114      * Matches given set of serializable fields with serializable fields
2115      * described by the given local class descriptor, and returns a
2116      * FieldReflector instance capable of setting/getting values from the
2117      * subset of fields that match (non-matching fields are treated as filler,
2118      * for which get operations return default values and set operations
2119      * discard given values).  Throws InvalidClassException if unresolvable
2120      * type conflicts exist between the two sets of fields.
2121      */
2122     private static FieldReflector getReflector(ObjectStreamField[] fields,
2123                                                ObjectStreamClass localDesc)
2124         throws InvalidClassException
2125     {

  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.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.reflect.Constructor;
  32 import java.lang.reflect.Field;
  33 import java.lang.reflect.InaccessibleObjectException;
  34 import java.lang.reflect.InvocationTargetException;
  35 import java.lang.reflect.RecordComponent;
  36 import java.lang.reflect.UndeclaredThrowableException;
  37 import java.lang.reflect.Member;
  38 import java.lang.reflect.Method;
  39 import java.lang.reflect.Modifier;
  40 import java.lang.reflect.Proxy;
  41 import java.security.AccessControlContext;
  42 import java.security.AccessController;
  43 import java.security.MessageDigest;
  44 import java.security.NoSuchAlgorithmException;
  45 import java.security.PermissionCollection;
  46 import java.security.Permissions;
  47 import java.security.PrivilegedAction;
  48 import java.security.PrivilegedActionException;
  49 import java.security.PrivilegedExceptionAction;
  50 import java.security.ProtectionDomain;
  51 import java.util.ArrayList;
  52 import java.util.Arrays;
  53 import java.util.Collections;

  55 import java.util.HashSet;
  56 import java.util.Map;
  57 import java.util.Set;
  58 import java.util.concurrent.ConcurrentHashMap;
  59 import jdk.internal.misc.Unsafe;
  60 import jdk.internal.reflect.CallerSensitive;
  61 import jdk.internal.reflect.Reflection;
  62 import jdk.internal.reflect.ReflectionFactory;
  63 import jdk.internal.access.SharedSecrets;
  64 import jdk.internal.access.JavaSecurityAccess;
  65 import jdk.internal.util.ByteArray;
  66 import sun.reflect.misc.ReflectUtil;
  67 
  68 /**
  69  * Serialization's descriptor for classes.  It contains the name and
  70  * serialVersionUID of the class.  The ObjectStreamClass for a specific class
  71  * loaded in this Java VM can be found/created using the lookup method.
  72  *
  73  * <p>The algorithm to compute the SerialVersionUID is described in
  74  * <a href="{@docRoot}/../specs/serialization/class.html#stream-unique-identifiers">
  75  *    <cite>Java Object Serialization Specification</cite>, Section 4.6, "Stream Unique Identifiers"</a>.
  76  *
  77  * @spec serialization/index.html Java Object Serialization Specification
  78  * @author      Mike Warres
  79  * @author      Roger Riggs
  80  * @see ObjectStreamField
  81  * @see <a href="{@docRoot}/../specs/serialization/class.html">
  82  *      <cite>Java Object Serialization Specification,</cite> Section 4, "Class Descriptors"</a>
  83  * @since   1.1
  84  */
  85 public final class ObjectStreamClass implements Serializable {
  86 
  87     /** serialPersistentFields value indicating no serializable fields */
  88     public static final ObjectStreamField[] NO_FIELDS =
  89         new ObjectStreamField[0];
  90 
  91     @java.io.Serial
  92     private static final long serialVersionUID = -6120832682080437368L;
  93     /**
  94      * {@code ObjectStreamClass} has no fields for default serialization.
  95      */

 119                 @Override
 120                 protected Map<FieldReflectorKey, FieldReflector> computeValue(Class<?> type) {
 121                     return new ConcurrentHashMap<>();
 122                 }
 123             };
 124     }
 125 
 126     /** class associated with this descriptor (if any) */
 127     private Class<?> cl;
 128     /** name of class represented by this descriptor */
 129     private String name;
 130     /** serialVersionUID of represented class (null if not computed yet) */
 131     private volatile Long suid;
 132 
 133     /** true if represents dynamic proxy class */
 134     private boolean isProxy;
 135     /** true if represents enum type */
 136     private boolean isEnum;
 137     /** true if represents record type */
 138     private boolean isRecord;
 139     /** true if represents a value class */
 140     private boolean isValue;
 141     /** true if represented class implements Serializable */
 142     private boolean serializable;
 143     /** true if represented class implements Externalizable */
 144     private boolean externalizable;
 145     /** true if desc has data written by class-defined writeObject method */
 146     private boolean hasWriteObjectData;
 147     /**
 148      * true if desc has externalizable data written in block data format; this
 149      * must be true by default to accommodate ObjectInputStream subclasses which
 150      * override readClassDescriptor() to return class descriptors obtained from
 151      * ObjectStreamClass.lookup() (see 4461737)
 152      */
 153     private boolean hasBlockExternalData = true;
 154 
 155     /**
 156      * Contains information about InvalidClassException instances to be thrown
 157      * when attempting operations on an invalid class. Note that instances of
 158      * this class are immutable and are potentially shared among
 159      * ObjectStreamClass instances.
 160      */

 360      * @param   all if true, return descriptors for all classes; if false, only
 361      *          return descriptors for serializable classes
 362      */
 363     static ObjectStreamClass lookup(Class<?> cl, boolean all) {
 364         if (!(all || Serializable.class.isAssignableFrom(cl))) {
 365             return null;
 366         }
 367         return Caches.localDescs.get(cl);
 368     }
 369 
 370     /**
 371      * Creates local class descriptor representing given class.
 372      */
 373     @SuppressWarnings("removal")
 374     private ObjectStreamClass(final Class<?> cl) {
 375         this.cl = cl;
 376         name = cl.getName();
 377         isProxy = Proxy.isProxyClass(cl);
 378         isEnum = Enum.class.isAssignableFrom(cl);
 379         isRecord = cl.isRecord();
 380         isValue = cl.isValue();
 381         serializable = Serializable.class.isAssignableFrom(cl);
 382         externalizable = Externalizable.class.isAssignableFrom(cl);
 383 
 384         Class<?> superCl = cl.getSuperclass();
 385         superDesc = (superCl != null) ? lookup(superCl, false) : null;
 386         localDesc = this;
 387 
 388         if (serializable) {
 389             AccessController.doPrivileged(new PrivilegedAction<>() {
 390                 public Void run() {
 391                     if (isEnum) {
 392                         suid = 0L;
 393                         fields = NO_FIELDS;
 394                         return null;
 395                     }
 396                     if (cl.isArray()) {
 397                         fields = NO_FIELDS;
 398                         return null;
 399                     }
 400 
 401                     suid = getDeclaredSUID(cl);
 402                     try {
 403                         fields = getSerialFields(cl);
 404                         computeFieldOffsets();
 405                     } catch (InvalidClassException e) {
 406                         serializeEx = deserializeEx =
 407                             new ExceptionInfo(e.classname, e.getMessage());
 408                         fields = NO_FIELDS;
 409                     }
 410 
 411                     if (isRecord) {
 412                         canonicalCtr = canonicalRecordCtr(cl);
 413                         deserializationCtrs = new DeserializationConstructorsCache();
 414                     } else if (isValue) {
 415                         // Value objects are created using Unsafe.
 416                         cons = null;
 417                     } else if (externalizable) {
 418                         cons = getExternalizableConstructor(cl);
 419                     } else {
 420                         cons = getSerializableConstructor(cl);
 421                         writeObjectMethod = getPrivateMethod(cl, "writeObject",
 422                             new Class<?>[] { ObjectOutputStream.class },
 423                             Void.TYPE);
 424                         readObjectMethod = getPrivateMethod(cl, "readObject",
 425                             new Class<?>[] { ObjectInputStream.class },
 426                             Void.TYPE);
 427                         readObjectNoDataMethod = getPrivateMethod(
 428                             cl, "readObjectNoData", null, Void.TYPE);
 429                         hasWriteObjectData = (writeObjectMethod != null);
 430                     }
 431                     domains = getProtectionDomains(cons, cl);
 432                     writeReplaceMethod = getInheritableMethod(
 433                         cl, "writeReplace", null, Object.class);
 434                     readResolveMethod = getInheritableMethod(
 435                         cl, "readResolve", null, Object.class);
 436                     return null;
 437                 }
 438             });
 439         } else {
 440             suid = 0L;
 441             fields = NO_FIELDS;
 442         }
 443 
 444         try {
 445             fieldRefl = getReflector(fields, this);
 446         } catch (InvalidClassException ex) {
 447             // field mismatches impossible when matching local fields vs. self
 448             throw new InternalError(ex);
 449         }
 450 
 451         if (deserializeEx == null) {
 452             if (isEnum) {
 453                 deserializeEx = new ExceptionInfo(name, "enum type");
 454             } else if (cons == null && !(isRecord | isValue)) {
 455                 deserializeEx = new ExceptionInfo(name, "no valid constructor");
 456             }
 457         }
 458         if (isRecord && canonicalCtr == null) {
 459             deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
 460         } else {
 461             for (int i = 0; i < fields.length; i++) {
 462                 if (fields[i].getField() == null) {
 463                     defaultSerializeEx = new ExceptionInfo(
 464                         name, "unmatched serializable field(s) declared");
 465                 }
 466             }
 467         }
 468         initialized = true;
 469     }
 470 
 471     /**
 472      * Creates blank class descriptor which should be initialized via a
 473      * subsequent call to initProxy(), initNonProxy() or readNonProxy().
 474      */

 628         }
 629 
 630         this.cl = cl;
 631         this.resolveEx = resolveEx;
 632         this.superDesc = superDesc;
 633         name = model.name;
 634         this.suid = suid;
 635         isProxy = false;
 636         isEnum = model.isEnum;
 637         serializable = model.serializable;
 638         externalizable = model.externalizable;
 639         hasBlockExternalData = model.hasBlockExternalData;
 640         hasWriteObjectData = model.hasWriteObjectData;
 641         fields = model.fields;
 642         primDataSize = model.primDataSize;
 643         numObjFields = model.numObjFields;
 644 
 645         if (osc != null) {
 646             localDesc = osc;
 647             isRecord = localDesc.isRecord;
 648             isValue = localDesc.isValue;
 649             // canonical record constructor is shared
 650             canonicalCtr = localDesc.canonicalCtr;
 651             // cache of deserialization constructors is shared
 652             deserializationCtrs = localDesc.deserializationCtrs;
 653             writeObjectMethod = localDesc.writeObjectMethod;
 654             readObjectMethod = localDesc.readObjectMethod;
 655             readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
 656             writeReplaceMethod = localDesc.writeReplaceMethod;
 657             readResolveMethod = localDesc.readResolveMethod;
 658             if (deserializeEx == null) {
 659                 deserializeEx = localDesc.deserializeEx;
 660             }
 661             domains = localDesc.domains;
 662             assert cl.isRecord() ? localDesc.cons == null : true;
 663             cons = localDesc.cons;
 664         }
 665 
 666         fieldRefl = getReflector(fields, localDesc);
 667         // reassign to matched fields so as to reflect local unshared settings
 668         fields = fieldRefl.getFields();

 910     }
 911 
 912     /**
 913      * Returns true if represented class implements Externalizable, false
 914      * otherwise.
 915      */
 916     boolean isExternalizable() {
 917         requireInitialized();
 918         return externalizable;
 919     }
 920 
 921     /**
 922      * Returns true if represented class implements Serializable, false
 923      * otherwise.
 924      */
 925     boolean isSerializable() {
 926         requireInitialized();
 927         return serializable;
 928     }
 929 
 930     /**
 931      * {@return {code true} if the class is a value class, {@code false} otherwise}
 932      */
 933     boolean isValue() {
 934         requireInitialized();
 935         return isValue;
 936     }
 937 
 938     /**
 939      * Returns true if class descriptor represents externalizable class that
 940      * has written its data in 1.2 (block data) format, false otherwise.
 941      */
 942     boolean hasBlockExternalData() {
 943         requireInitialized();
 944         return hasBlockExternalData;
 945     }
 946 
 947     /**
 948      * Returns true if class descriptor represents serializable (but not
 949      * externalizable) class which has written its data via a custom
 950      * writeObject() method, false otherwise.
 951      */
 952     boolean hasWriteObjectData() {
 953         requireInitialized();
 954         return hasWriteObjectData;
 955     }
 956 
 957     /**
 958      * Returns true if represented class is serializable/externalizable and can
 959      * be instantiated by the serialization runtime--i.e., if it is
 960      * externalizable and defines a public no-arg constructor, if it is
 961      * non-externalizable and its first non-serializable superclass defines an
 962      * accessible no-arg constructor, or if the class is a value class.
 963      * Otherwise, returns false.
 964      */
 965     boolean isInstantiable() {
 966         requireInitialized();
 967         return (cons != null | isValue);
 968     }
 969 
 970     /**
 971      * Returns true if represented class is serializable (but not
 972      * externalizable) and defines a conformant writeObject method.  Otherwise,
 973      * returns false.
 974      */
 975     boolean hasWriteObjectMethod() {
 976         requireInitialized();
 977         return (writeObjectMethod != null);
 978     }
 979 
 980     /**
 981      * Returns true if represented class is serializable (but not
 982      * externalizable) and defines a conformant readObject method.  Otherwise,
 983      * returns false.
 984      */
 985     boolean hasReadObjectMethod() {
 986         requireInitialized();
 987         return (readObjectMethod != null);

1058                         if (cause instanceof IllegalAccessException iae)
1059                             throw iae;
1060                         // not supposed to happen
1061                         throw x;
1062                     }
1063                 }
1064             } catch (IllegalAccessException ex) {
1065                 // should not occur, as access checks have been suppressed
1066                 throw new InternalError(ex);
1067             } catch (InvocationTargetException ex) {
1068                 Throwable cause = ex.getCause();
1069                 if (cause instanceof Error err)
1070                     throw err;
1071                 else
1072                     throw ex;
1073             } catch (InstantiationError err) {
1074                 var ex = new InstantiationException();
1075                 ex.initCause(err);
1076                 throw ex;
1077             }
1078         } else if (isValue) {
1079             // Start with a buffered default value.
1080             return FieldReflector.newValueInstance(cl);
1081         }  else {
1082             throw new UnsupportedOperationException();
1083         }
1084     }
1085 
1086     /**
1087      * Finish the initialization of a value object.
1088      * @param obj an object (larval if a value object)
1089      * @return the finished object
1090      */
1091     Object finishValue(Object obj) {
1092         return (isValue) ? FieldReflector.finishValueInstance(obj) : obj;
1093     }
1094 
1095     /**
1096      * Invokes the writeObject method of the represented serializable class.
1097      * Throws UnsupportedOperationException if this class descriptor is not
1098      * associated with a class, or if the class is externalizable,
1099      * non-serializable or does not define writeObject.
1100      */
1101     void invokeWriteObject(Object obj, ObjectOutputStream out)
1102         throws IOException, UnsupportedOperationException
1103     {
1104         requireInitialized();
1105         if (writeObjectMethod != null) {
1106             try {
1107                 writeObjectMethod.invoke(obj, new Object[]{ out });
1108             } catch (InvocationTargetException ex) {
1109                 Throwable th = ex.getCause();
1110                 if (th instanceof IOException) {
1111                     throw (IOException) th;
1112                 } else {
1113                     throwMiscException(th);
1114                 }

1449         ObjectStreamClass desc = new ObjectStreamClass();
1450         if (isProxy) {
1451             desc.initProxy(cl, null, superDesc);
1452         } else {
1453             desc.initNonProxy(this, cl, null, superDesc);
1454         }
1455         return desc;
1456     }
1457 
1458     /**
1459      * Returns public no-arg constructor of given class, or null if none found.
1460      * Access checks are disabled on the returned constructor (if any), since
1461      * the defining class may still be non-public.
1462      */
1463     private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1464         try {
1465             Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1466             cons.setAccessible(true);
1467             return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1468                 cons : null;
1469         } catch (NoSuchMethodException | InaccessibleObjectException ex) {
1470             return null;
1471         }
1472     }
1473 
1474     /**
1475      * Returns subclass-accessible no-arg constructor of first non-serializable
1476      * superclass, or null if none found.  Access checks are disabled on the
1477      * returned constructor (if any).
1478      */
1479     private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1480         return reflFactory.newConstructorForSerialization(cl);
1481     }
1482 
1483     /**
1484      * Returns the canonical constructor for the given record class, or null if
1485      * the not found ( which should never happen for correctly generated record
1486      * classes ).
1487      */
1488     @SuppressWarnings("removal")
1489     private static MethodHandle canonicalRecordCtr(Class<?> cls) {

1942     private static final class FieldReflector {
1943 
1944         /** handle for performing unsafe operations */
1945         private static final Unsafe UNSAFE = Unsafe.getUnsafe();
1946 
1947         /** fields to operate on */
1948         private final ObjectStreamField[] fields;
1949         /** number of primitive fields */
1950         private final int numPrimFields;
1951         /** unsafe field keys for reading fields - may contain dupes */
1952         private final long[] readKeys;
1953         /** unsafe fields keys for writing fields - no dupes */
1954         private final long[] writeKeys;
1955         /** field data offsets */
1956         private final int[] offsets;
1957         /** field type codes */
1958         private final char[] typeCodes;
1959         /** field types */
1960         private final Class<?>[] types;
1961 
1962         /**
1963          * Return a new instance of the class using Unsafe.uninitializedDefaultValue
1964          * and buffer it.
1965          * @param clazz The value class
1966          * @return a buffered default value
1967          */
1968         static Object newValueInstance(Class<?> clazz) throws InstantiationException{
1969             assert clazz.isValue() : "Should be a value class";
1970             // may not be implicitly constructible; so allocate with Unsafe
1971             Object obj = UNSAFE.uninitializedDefaultValue(clazz);
1972             return UNSAFE.makePrivateBuffer(obj);
1973         }
1974 
1975         /**
1976          * Finish a value object, clear the larval state and returning the value object.
1977          * @param obj a buffered value object in a larval state
1978          * @return the finished value object
1979          */
1980         static Object finishValueInstance(Object obj) {
1981             assert (obj.getClass().isValue()) : "Should be a value class";
1982             return UNSAFE.finishPrivateBuffer(obj);
1983         }
1984 
1985         /**
1986          * Constructs FieldReflector capable of setting/getting values from the
1987          * subset of fields whose ObjectStreamFields contain non-null
1988          * reflective Field objects.  ObjectStreamFields with null Fields are
1989          * treated as filler, for which get operations return default values
1990          * and set operations discard given values.
1991          */
1992         FieldReflector(ObjectStreamField[] fields) {
1993             this.fields = fields;
1994             int nfields = fields.length;
1995             readKeys = new long[nfields];
1996             writeKeys = new long[nfields];
1997             offsets = new int[nfields];
1998             typeCodes = new char[nfields];
1999             ArrayList<Class<?>> typeList = new ArrayList<>();
2000             Set<Long> usedKeys = new HashSet<>();
2001 
2002 
2003             for (int i = 0; i < nfields; i++) {
2004                 ObjectStreamField f = fields[i];

2085                     case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off));
2086                     default  -> throw new InternalError();
2087                 }
2088             }
2089         }
2090 
2091         /**
2092          * Fetches the serializable object field values of object obj and
2093          * stores them in array vals starting at offset 0.  The caller is
2094          * responsible for ensuring that obj is of the proper type.
2095          */
2096         void getObjFieldValues(Object obj, Object[] vals) {
2097             if (obj == null) {
2098                 throw new NullPointerException();
2099             }
2100             /* assuming checkDefaultSerialize() has been called on the class
2101              * descriptor this FieldReflector was obtained from, no field keys
2102              * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2103              */
2104             for (int i = numPrimFields; i < fields.length; i++) {
2105                 Field f = fields[i].getField();
2106                 vals[offsets[i]] = switch (typeCodes[i]) {
2107                     case 'L', '[' ->
2108                             UNSAFE.isFlatField(f)
2109                                     ? UNSAFE.getValue(obj, readKeys[i], f.getType())
2110                                     : UNSAFE.getReference(obj, readKeys[i]);
2111                     default       -> throw new InternalError();
2112                 };
2113             }
2114         }
2115 
2116         /**
2117          * Checks that the given values, from array vals starting at offset 0,
2118          * are assignable to the given serializable object fields.
2119          * @throws ClassCastException if any value is not assignable
2120          */
2121         void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2122             setObjFieldValues(obj, vals, true);
2123         }
2124 
2125         /**
2126          * Sets the serializable object fields of object obj using values from
2127          * array vals starting at offset 0.  The caller is responsible for
2128          * ensuring that obj is of the proper type; however, attempts to set a
2129          * field with a value of the wrong type will trigger an appropriate
2130          * ClassCastException.
2131          */
2132         void setObjFieldValues(Object obj, Object[] vals) {
2133             setObjFieldValues(obj, vals, false);
2134         }
2135 
2136         private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2137             if (obj == null) {
2138                 throw new NullPointerException();
2139             }
2140             for (int i = numPrimFields; i < fields.length; i++) {
2141                 long key = writeKeys[i];
2142                 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2143                     continue;           // discard value
2144                 }
2145                 switch (typeCodes[i]) {
2146                     case 'L', '[' -> {
2147                         Field f = fields[i].getField();
2148                         Object val = vals[offsets[i]];
2149                         if (val != null &&
2150                             !types[i - numPrimFields].isInstance(val))
2151                         {

2152                             throw new ClassCastException(
2153                                 "cannot assign instance of " +
2154                                 val.getClass().getName() + " to field " +
2155                                 f.getDeclaringClass().getName() + "." +
2156                                 f.getName() + " of type " +
2157                                 f.getType().getName() + " in instance of " +
2158                                 obj.getClass().getName());
2159                         }
2160                         if (!dryRun) {
2161                             if (UNSAFE.isFlatField(f)) {
2162                                 UNSAFE.putValue(obj, key, f.getType(), val);
2163                             } else {
2164                                 UNSAFE.putReference(obj, key, val);
2165                             }
2166                         }
2167                     }
2168                     default -> throw new InternalError();
2169                 }
2170             }
2171         }
2172     }
2173 
2174     /**
2175      * Matches given set of serializable fields with serializable fields
2176      * described by the given local class descriptor, and returns a
2177      * FieldReflector instance capable of setting/getting values from the
2178      * subset of fields that match (non-matching fields are treated as filler,
2179      * for which get operations return default values and set operations
2180      * discard given values).  Throws InvalidClassException if unresolvable
2181      * type conflicts exist between the two sets of fields.
2182      */
2183     private static FieldReflector getReflector(ObjectStreamField[] fields,
2184                                                ObjectStreamClass localDesc)
2185         throws InvalidClassException
2186     {
< prev index next >