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);
1035 } catch (UndeclaredThrowableException x) {
1036 Throwable cause = x.getCause();
1037 if (cause instanceof InstantiationException)
1038 throw (InstantiationException) cause;
1039 if (cause instanceof InvocationTargetException)
1040 throw (InvocationTargetException) cause;
1041 if (cause instanceof IllegalAccessException)
1042 throw (IllegalAccessException) cause;
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 (InstantiationError err) {
1051 var ex = new InstantiationException();
1052 ex.initCause(err);
1053 throw ex;
1054 }
1055 } else {
1056 throw new UnsupportedOperationException();
1057 }
1058 }
1059
1060 /**
1061 * Invokes the writeObject method of the represented serializable class.
1062 * Throws UnsupportedOperationException if this class descriptor is not
1063 * associated with a class, or if the class is externalizable,
1064 * non-serializable or does not define writeObject.
1065 */
1066 void invokeWriteObject(Object obj, ObjectOutputStream out)
1067 throws IOException, UnsupportedOperationException
1068 {
1069 requireInitialized();
1070 if (writeObjectMethod != null) {
1071 try {
1072 writeObjectMethod.invoke(obj, new Object[]{ out });
1073 } catch (InvocationTargetException ex) {
1074 Throwable th = ex.getCause();
1075 if (th instanceof IOException) {
1076 throw (IOException) th;
1077 } else {
1078 throwMiscException(th);
1079 }
1414 ObjectStreamClass desc = new ObjectStreamClass();
1415 if (isProxy) {
1416 desc.initProxy(cl, null, superDesc);
1417 } else {
1418 desc.initNonProxy(this, cl, null, superDesc);
1419 }
1420 return desc;
1421 }
1422
1423 /**
1424 * Returns public no-arg constructor of given class, or null if none found.
1425 * Access checks are disabled on the returned constructor (if any), since
1426 * the defining class may still be non-public.
1427 */
1428 private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1429 try {
1430 Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1431 cons.setAccessible(true);
1432 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1433 cons : null;
1434 } catch (NoSuchMethodException ex) {
1435 return null;
1436 }
1437 }
1438
1439 /**
1440 * Returns subclass-accessible no-arg constructor of first non-serializable
1441 * superclass, or null if none found. Access checks are disabled on the
1442 * returned constructor (if any).
1443 */
1444 private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1445 return reflFactory.newConstructorForSerialization(cl);
1446 }
1447
1448 /**
1449 * Returns the canonical constructor for the given record class, or null if
1450 * the not found ( which should never happen for correctly generated record
1451 * classes ).
1452 */
1453 @SuppressWarnings("removal")
1454 private static MethodHandle canonicalRecordCtr(Class<?> cls) {
1907 private static final class FieldReflector {
1908
1909 /** handle for performing unsafe operations */
1910 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
1911
1912 /** fields to operate on */
1913 private final ObjectStreamField[] fields;
1914 /** number of primitive fields */
1915 private final int numPrimFields;
1916 /** unsafe field keys for reading fields - may contain dupes */
1917 private final long[] readKeys;
1918 /** unsafe fields keys for writing fields - no dupes */
1919 private final long[] writeKeys;
1920 /** field data offsets */
1921 private final int[] offsets;
1922 /** field type codes */
1923 private final char[] typeCodes;
1924 /** field types */
1925 private final Class<?>[] types;
1926
1927 /**
1928 * Constructs FieldReflector capable of setting/getting values from the
1929 * subset of fields whose ObjectStreamFields contain non-null
1930 * reflective Field objects. ObjectStreamFields with null Fields are
1931 * treated as filler, for which get operations return default values
1932 * and set operations discard given values.
1933 */
1934 FieldReflector(ObjectStreamField[] fields) {
1935 this.fields = fields;
1936 int nfields = fields.length;
1937 readKeys = new long[nfields];
1938 writeKeys = new long[nfields];
1939 offsets = new int[nfields];
1940 typeCodes = new char[nfields];
1941 ArrayList<Class<?>> typeList = new ArrayList<>();
1942 Set<Long> usedKeys = new HashSet<>();
1943
1944
1945 for (int i = 0; i < nfields; i++) {
1946 ObjectStreamField f = fields[i];
2027 case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off));
2028 default -> throw new InternalError();
2029 }
2030 }
2031 }
2032
2033 /**
2034 * Fetches the serializable object field values of object obj and
2035 * stores them in array vals starting at offset 0. The caller is
2036 * responsible for ensuring that obj is of the proper type.
2037 */
2038 void getObjFieldValues(Object obj, Object[] vals) {
2039 if (obj == null) {
2040 throw new NullPointerException();
2041 }
2042 /* assuming checkDefaultSerialize() has been called on the class
2043 * descriptor this FieldReflector was obtained from, no field keys
2044 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2045 */
2046 for (int i = numPrimFields; i < fields.length; i++) {
2047 vals[offsets[i]] = switch (typeCodes[i]) {
2048 case 'L', '[' -> UNSAFE.getReference(obj, readKeys[i]);
2049 default -> throw new InternalError();
2050 };
2051 }
2052 }
2053
2054 /**
2055 * Checks that the given values, from array vals starting at offset 0,
2056 * are assignable to the given serializable object fields.
2057 * @throws ClassCastException if any value is not assignable
2058 */
2059 void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2060 setObjFieldValues(obj, vals, true);
2061 }
2062
2063 /**
2064 * Sets the serializable object fields of object obj using values from
2065 * array vals starting at offset 0. The caller is responsible for
2066 * ensuring that obj is of the proper type; however, attempts to set a
2067 * field with a value of the wrong type will trigger an appropriate
2068 * ClassCastException.
2069 */
2070 void setObjFieldValues(Object obj, Object[] vals) {
2071 setObjFieldValues(obj, vals, false);
2072 }
2073
2074 private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2075 if (obj == null) {
2076 throw new NullPointerException();
2077 }
2078 for (int i = numPrimFields; i < fields.length; i++) {
2079 long key = writeKeys[i];
2080 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2081 continue; // discard value
2082 }
2083 switch (typeCodes[i]) {
2084 case 'L', '[' -> {
2085 Object val = vals[offsets[i]];
2086 if (val != null &&
2087 !types[i - numPrimFields].isInstance(val))
2088 {
2089 Field f = fields[i].getField();
2090 throw new ClassCastException(
2091 "cannot assign instance of " +
2092 val.getClass().getName() + " to field " +
2093 f.getDeclaringClass().getName() + "." +
2094 f.getName() + " of type " +
2095 f.getType().getName() + " in instance of " +
2096 obj.getClass().getName());
2097 }
2098 if (!dryRun)
2099 UNSAFE.putReference(obj, key, val);
2100 }
2101 default -> throw new InternalError();
2102 }
2103 }
2104 }
2105 }
2106
2107 /**
2108 * Matches given set of serializable fields with serializable fields
2109 * described by the given local class descriptor, and returns a
2110 * FieldReflector instance capable of setting/getting values from the
2111 * subset of fields that match (non-matching fields are treated as filler,
2112 * for which get operations return default values and set operations
2113 * discard given values). Throws InvalidClassException if unresolvable
2114 * type conflicts exist between the two sets of fields.
2115 */
2116 private static FieldReflector getReflector(ObjectStreamField[] fields,
2117 ObjectStreamClass localDesc)
2118 throws InvalidClassException
2119 {
|
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);
1052 } catch (UndeclaredThrowableException x) {
1053 Throwable cause = x.getCause();
1054 if (cause instanceof InstantiationException)
1055 throw (InstantiationException) cause;
1056 if (cause instanceof InvocationTargetException)
1057 throw (InvocationTargetException) cause;
1058 if (cause instanceof IllegalAccessException)
1059 throw (IllegalAccessException) cause;
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 (InstantiationError err) {
1068 var ex = new InstantiationException();
1069 ex.initCause(err);
1070 throw ex;
1071 }
1072 } else if (isValue) {
1073 // Start with a buffered default value.
1074 return FieldReflector.newValueInstance(cl);
1075 } else {
1076 throw new UnsupportedOperationException();
1077 }
1078 }
1079
1080 /**
1081 * Finish the initialization of a value object.
1082 * @param obj an object (larval if a value object)
1083 * @return the finished object
1084 */
1085 Object finishValue(Object obj) {
1086 return (isValue) ? FieldReflector.finishValueInstance(obj) : obj;
1087 }
1088
1089 /**
1090 * Invokes the writeObject method of the represented serializable class.
1091 * Throws UnsupportedOperationException if this class descriptor is not
1092 * associated with a class, or if the class is externalizable,
1093 * non-serializable or does not define writeObject.
1094 */
1095 void invokeWriteObject(Object obj, ObjectOutputStream out)
1096 throws IOException, UnsupportedOperationException
1097 {
1098 requireInitialized();
1099 if (writeObjectMethod != null) {
1100 try {
1101 writeObjectMethod.invoke(obj, new Object[]{ out });
1102 } catch (InvocationTargetException ex) {
1103 Throwable th = ex.getCause();
1104 if (th instanceof IOException) {
1105 throw (IOException) th;
1106 } else {
1107 throwMiscException(th);
1108 }
1443 ObjectStreamClass desc = new ObjectStreamClass();
1444 if (isProxy) {
1445 desc.initProxy(cl, null, superDesc);
1446 } else {
1447 desc.initNonProxy(this, cl, null, superDesc);
1448 }
1449 return desc;
1450 }
1451
1452 /**
1453 * Returns public no-arg constructor of given class, or null if none found.
1454 * Access checks are disabled on the returned constructor (if any), since
1455 * the defining class may still be non-public.
1456 */
1457 private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1458 try {
1459 Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1460 cons.setAccessible(true);
1461 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1462 cons : null;
1463 } catch (NoSuchMethodException | InaccessibleObjectException ex) {
1464 return null;
1465 }
1466 }
1467
1468 /**
1469 * Returns subclass-accessible no-arg constructor of first non-serializable
1470 * superclass, or null if none found. Access checks are disabled on the
1471 * returned constructor (if any).
1472 */
1473 private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1474 return reflFactory.newConstructorForSerialization(cl);
1475 }
1476
1477 /**
1478 * Returns the canonical constructor for the given record class, or null if
1479 * the not found ( which should never happen for correctly generated record
1480 * classes ).
1481 */
1482 @SuppressWarnings("removal")
1483 private static MethodHandle canonicalRecordCtr(Class<?> cls) {
1936 private static final class FieldReflector {
1937
1938 /** handle for performing unsafe operations */
1939 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
1940
1941 /** fields to operate on */
1942 private final ObjectStreamField[] fields;
1943 /** number of primitive fields */
1944 private final int numPrimFields;
1945 /** unsafe field keys for reading fields - may contain dupes */
1946 private final long[] readKeys;
1947 /** unsafe fields keys for writing fields - no dupes */
1948 private final long[] writeKeys;
1949 /** field data offsets */
1950 private final int[] offsets;
1951 /** field type codes */
1952 private final char[] typeCodes;
1953 /** field types */
1954 private final Class<?>[] types;
1955
1956 /**
1957 * Return a new instance of the class using Unsafe.uninitializedDefaultValue
1958 * and buffer it.
1959 * @param clazz The value class
1960 * @return a buffered default value
1961 */
1962 static Object newValueInstance(Class<?> clazz) throws InstantiationException{
1963 assert clazz.isValue() : "Should be a value class";
1964 Object obj = UNSAFE.uninitializedDefaultValue(clazz);
1965 return UNSAFE.makePrivateBuffer(obj);
1966 }
1967
1968 /**
1969 * Finish a value object, clear the larval state and returning the value object.
1970 * @param obj a buffered value object in a larval state
1971 * @return the finished value object
1972 */
1973 static Object finishValueInstance(Object obj) {
1974 assert (obj.getClass().isValue()) : "Should be a value class";
1975 return UNSAFE.finishPrivateBuffer(obj);
1976 }
1977
1978 /**
1979 * Constructs FieldReflector capable of setting/getting values from the
1980 * subset of fields whose ObjectStreamFields contain non-null
1981 * reflective Field objects. ObjectStreamFields with null Fields are
1982 * treated as filler, for which get operations return default values
1983 * and set operations discard given values.
1984 */
1985 FieldReflector(ObjectStreamField[] fields) {
1986 this.fields = fields;
1987 int nfields = fields.length;
1988 readKeys = new long[nfields];
1989 writeKeys = new long[nfields];
1990 offsets = new int[nfields];
1991 typeCodes = new char[nfields];
1992 ArrayList<Class<?>> typeList = new ArrayList<>();
1993 Set<Long> usedKeys = new HashSet<>();
1994
1995
1996 for (int i = 0; i < nfields; i++) {
1997 ObjectStreamField f = fields[i];
2078 case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off));
2079 default -> throw new InternalError();
2080 }
2081 }
2082 }
2083
2084 /**
2085 * Fetches the serializable object field values of object obj and
2086 * stores them in array vals starting at offset 0. The caller is
2087 * responsible for ensuring that obj is of the proper type.
2088 */
2089 void getObjFieldValues(Object obj, Object[] vals) {
2090 if (obj == null) {
2091 throw new NullPointerException();
2092 }
2093 /* assuming checkDefaultSerialize() has been called on the class
2094 * descriptor this FieldReflector was obtained from, no field keys
2095 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2096 */
2097 for (int i = numPrimFields; i < fields.length; i++) {
2098 Field f = fields[i].getField();
2099 vals[offsets[i]] = switch (typeCodes[i]) {
2100 case 'L', '[' ->
2101 UNSAFE.isFlattened(f)
2102 ? UNSAFE.getValue(obj, readKeys[i], f.getType())
2103 : UNSAFE.getReference(obj, readKeys[i]);
2104 default -> throw new InternalError();
2105 };
2106 }
2107 }
2108
2109 /**
2110 * Checks that the given values, from array vals starting at offset 0,
2111 * are assignable to the given serializable object fields.
2112 * @throws ClassCastException if any value is not assignable
2113 */
2114 void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2115 setObjFieldValues(obj, vals, true);
2116 }
2117
2118 /**
2119 * Sets the serializable object fields of object obj using values from
2120 * array vals starting at offset 0. The caller is responsible for
2121 * ensuring that obj is of the proper type; however, attempts to set a
2122 * field with a value of the wrong type will trigger an appropriate
2123 * ClassCastException.
2124 */
2125 void setObjFieldValues(Object obj, Object[] vals) {
2126 setObjFieldValues(obj, vals, false);
2127 }
2128
2129 private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2130 if (obj == null) {
2131 throw new NullPointerException();
2132 }
2133 for (int i = numPrimFields; i < fields.length; i++) {
2134 long key = writeKeys[i];
2135 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2136 continue; // discard value
2137 }
2138 switch (typeCodes[i]) {
2139 case 'L', '[' -> {
2140 Field f = fields[i].getField();
2141 Object val = vals[offsets[i]];
2142 if (val != null &&
2143 !types[i - numPrimFields].isInstance(val))
2144 {
2145 throw new ClassCastException(
2146 "cannot assign instance of " +
2147 val.getClass().getName() + " to field " +
2148 f.getDeclaringClass().getName() + "." +
2149 f.getName() + " of type " +
2150 f.getType().getName() + " in instance of " +
2151 obj.getClass().getName());
2152 }
2153 if (!dryRun) {
2154 if (UNSAFE.isFlattened(f)) {
2155 UNSAFE.putValue(obj, key, f.getType(), val);
2156 } else {
2157 UNSAFE.putReference(obj, key, val);
2158 }
2159 }
2160 }
2161 default -> throw new InternalError();
2162 }
2163 }
2164 }
2165 }
2166
2167 /**
2168 * Matches given set of serializable fields with serializable fields
2169 * described by the given local class descriptor, and returns a
2170 * FieldReflector instance capable of setting/getting values from the
2171 * subset of fields that match (non-matching fields are treated as filler,
2172 * for which get operations return default values and set operations
2173 * discard given values). Throws InvalidClassException if unresolvable
2174 * type conflicts exist between the two sets of fields.
2175 */
2176 private static FieldReflector getReflector(ObjectStreamField[] fields,
2177 ObjectStreamClass localDesc)
2178 throws InvalidClassException
2179 {
|