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;
53 import java.util.Comparator;
54 import java.util.HashSet;
55 import java.util.Map;
56 import java.util.Set;
57 import java.util.concurrent.ConcurrentHashMap;
58
59 import jdk.internal.event.SerializationMisdeclarationEvent;
60 import jdk.internal.misc.Unsafe;
61 import jdk.internal.reflect.CallerSensitive;
62 import jdk.internal.reflect.Reflection;
63 import jdk.internal.reflect.ReflectionFactory;
64 import jdk.internal.access.SharedSecrets;
65 import jdk.internal.access.JavaSecurityAccess;
66 import jdk.internal.util.ByteArray;
67 import sun.reflect.misc.ReflectUtil;
68
69 /**
70 * Serialization's descriptor for classes. It contains the name and
71 * serialVersionUID of the class. The ObjectStreamClass for a specific class
72 * loaded in this Java VM can be found/created using the lookup method.
73 *
74 * <p>The algorithm to compute the SerialVersionUID is described in
75 * <a href="{@docRoot}/../specs/serialization/class.html#stream-unique-identifiers">
76 * <cite>Java Object Serialization Specification,</cite> Section 4.6, "Stream Unique Identifiers"</a>.
77 *
78 * @spec serialization/index.html Java Object Serialization Specification
79 * @author Mike Warres
80 * @author Roger Riggs
81 * @see ObjectStreamField
82 * @see <a href="{@docRoot}/../specs/serialization/class.html">
83 * <cite>Java Object Serialization Specification,</cite> Section 4, "Class Descriptors"</a>
84 * @since 1.1
85 */
86 public final class ObjectStreamClass implements Serializable {
87
88 /** serialPersistentFields value indicating no serializable fields */
89 public static final ObjectStreamField[] NO_FIELDS =
90 new ObjectStreamField[0];
91
92 @java.io.Serial
93 private static final long serialVersionUID = -6120832682080437368L;
94 /**
95 * {@code ObjectStreamClass} has no fields for default serialization.
96 */
120 @Override
121 protected Map<FieldReflectorKey, FieldReflector> computeValue(Class<?> type) {
122 return new ConcurrentHashMap<>();
123 }
124 };
125 }
126
127 /** class associated with this descriptor (if any) */
128 private Class<?> cl;
129 /** name of class represented by this descriptor */
130 private String name;
131 /** serialVersionUID of represented class (null if not computed yet) */
132 private volatile Long suid;
133
134 /** true if represents dynamic proxy class */
135 private boolean isProxy;
136 /** true if represents enum type */
137 private boolean isEnum;
138 /** true if represents record type */
139 private boolean isRecord;
140 /** true if represented class implements Serializable */
141 private boolean serializable;
142 /** true if represented class implements Externalizable */
143 private boolean externalizable;
144 /** true if desc has data written by class-defined writeObject method */
145 private boolean hasWriteObjectData;
146 /**
147 * true if desc has externalizable data written in block data format; this
148 * must be true by default to accommodate ObjectInputStream subclasses which
149 * override readClassDescriptor() to return class descriptors obtained from
150 * ObjectStreamClass.lookup() (see 4461737)
151 */
152 private boolean hasBlockExternalData = true;
153
154 /**
155 * Contains information about InvalidClassException instances to be thrown
156 * when attempting operations on an invalid class. Note that instances of
157 * this class are immutable and are potentially shared among
158 * ObjectStreamClass instances.
159 */
359 * @param all if true, return descriptors for all classes; if false, only
360 * return descriptors for serializable classes
361 */
362 static ObjectStreamClass lookup(Class<?> cl, boolean all) {
363 if (!(all || Serializable.class.isAssignableFrom(cl))) {
364 return null;
365 }
366 return Caches.localDescs.get(cl);
367 }
368
369 /**
370 * Creates local class descriptor representing given class.
371 */
372 @SuppressWarnings("removal")
373 private ObjectStreamClass(final Class<?> cl) {
374 this.cl = cl;
375 name = cl.getName();
376 isProxy = Proxy.isProxyClass(cl);
377 isEnum = Enum.class.isAssignableFrom(cl);
378 isRecord = cl.isRecord();
379 serializable = Serializable.class.isAssignableFrom(cl);
380 externalizable = Externalizable.class.isAssignableFrom(cl);
381
382 Class<?> superCl = cl.getSuperclass();
383 superDesc = (superCl != null) ? lookup(superCl, false) : null;
384 localDesc = this;
385
386 if (serializable) {
387 AccessController.doPrivileged(new PrivilegedAction<>() {
388 public Void run() {
389 if (isEnum) {
390 suid = 0L;
391 fields = NO_FIELDS;
392 return null;
393 }
394 if (cl.isArray()) {
395 fields = NO_FIELDS;
396 return null;
397 }
398
399 suid = getDeclaredSUID(cl);
400 try {
401 fields = getSerialFields(cl);
402 computeFieldOffsets();
403 } catch (InvalidClassException e) {
404 serializeEx = deserializeEx =
405 new ExceptionInfo(e.classname, e.getMessage());
406 fields = NO_FIELDS;
407 }
408
409 if (isRecord) {
410 canonicalCtr = canonicalRecordCtr(cl);
411 deserializationCtrs = new DeserializationConstructorsCache();
412 } else if (externalizable) {
413 cons = getExternalizableConstructor(cl);
414 } else {
415 cons = getSerializableConstructor(cl);
416 writeObjectMethod = getPrivateMethod(cl, "writeObject",
417 new Class<?>[] { ObjectOutputStream.class },
418 Void.TYPE);
419 readObjectMethod = getPrivateMethod(cl, "readObject",
420 new Class<?>[] { ObjectInputStream.class },
421 Void.TYPE);
422 readObjectNoDataMethod = getPrivateMethod(
423 cl, "readObjectNoData", null, Void.TYPE);
424 hasWriteObjectData = (writeObjectMethod != null);
425 }
426 domains = getProtectionDomains(cons, cl);
427 writeReplaceMethod = getInheritableMethod(
428 cl, "writeReplace", null, Object.class);
429 readResolveMethod = getInheritableMethod(
430 cl, "readResolve", null, Object.class);
431 return null;
432 }
433 });
434 } else {
435 suid = 0L;
436 fields = NO_FIELDS;
437 }
438
439 try {
440 fieldRefl = getReflector(fields, this);
441 } catch (InvalidClassException ex) {
442 // field mismatches impossible when matching local fields vs. self
443 throw new InternalError(ex);
444 }
445
446 if (deserializeEx == null) {
447 if (isEnum) {
448 deserializeEx = new ExceptionInfo(name, "enum type");
449 } else if (cons == null && !isRecord) {
450 deserializeEx = new ExceptionInfo(name, "no valid constructor");
451 }
452 }
453 if (isRecord && canonicalCtr == null) {
454 deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
455 } else {
456 for (int i = 0; i < fields.length; i++) {
457 if (fields[i].getField() == null) {
458 defaultSerializeEx = new ExceptionInfo(
459 name, "unmatched serializable field(s) declared");
460 }
461 }
462 }
463 initialized = true;
464
465 if (SerializationMisdeclarationEvent.enabled() && serializable) {
466 SerializationMisdeclarationChecker.checkMisdeclarations(cl);
467 }
468 }
469
627 }
628
629 this.cl = cl;
630 this.resolveEx = resolveEx;
631 this.superDesc = superDesc;
632 name = model.name;
633 this.suid = suid;
634 isProxy = false;
635 isEnum = model.isEnum;
636 serializable = model.serializable;
637 externalizable = model.externalizable;
638 hasBlockExternalData = model.hasBlockExternalData;
639 hasWriteObjectData = model.hasWriteObjectData;
640 fields = model.fields;
641 primDataSize = model.primDataSize;
642 numObjFields = model.numObjFields;
643
644 if (osc != null) {
645 localDesc = osc;
646 isRecord = localDesc.isRecord;
647 // canonical record constructor is shared
648 canonicalCtr = localDesc.canonicalCtr;
649 // cache of deserialization constructors is shared
650 deserializationCtrs = localDesc.deserializationCtrs;
651 writeObjectMethod = localDesc.writeObjectMethod;
652 readObjectMethod = localDesc.readObjectMethod;
653 readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
654 writeReplaceMethod = localDesc.writeReplaceMethod;
655 readResolveMethod = localDesc.readResolveMethod;
656 if (deserializeEx == null) {
657 deserializeEx = localDesc.deserializeEx;
658 }
659 domains = localDesc.domains;
660 assert cl.isRecord() ? localDesc.cons == null : true;
661 cons = localDesc.cons;
662 }
663
664 fieldRefl = getReflector(fields, localDesc);
665 // reassign to matched fields so as to reflect local unshared settings
666 fields = fieldRefl.getFields();
908 }
909
910 /**
911 * Returns true if represented class implements Externalizable, false
912 * otherwise.
913 */
914 boolean isExternalizable() {
915 requireInitialized();
916 return externalizable;
917 }
918
919 /**
920 * Returns true if represented class implements Serializable, false
921 * otherwise.
922 */
923 boolean isSerializable() {
924 requireInitialized();
925 return serializable;
926 }
927
928 /**
929 * Returns true if class descriptor represents externalizable class that
930 * has written its data in 1.2 (block data) format, false otherwise.
931 */
932 boolean hasBlockExternalData() {
933 requireInitialized();
934 return hasBlockExternalData;
935 }
936
937 /**
938 * Returns true if class descriptor represents serializable (but not
939 * externalizable) class which has written its data via a custom
940 * writeObject() method, false otherwise.
941 */
942 boolean hasWriteObjectData() {
943 requireInitialized();
944 return hasWriteObjectData;
945 }
946
947 /**
948 * Returns true if represented class is serializable/externalizable and can
949 * be instantiated by the serialization runtime--i.e., if it is
950 * externalizable and defines a public no-arg constructor, or if it is
951 * non-externalizable and its first non-serializable superclass defines an
952 * accessible no-arg constructor. Otherwise, returns false.
953 */
954 boolean isInstantiable() {
955 requireInitialized();
956 return (cons != null);
957 }
958
959 /**
960 * Returns true if represented class is serializable (but not
961 * externalizable) and defines a conformant writeObject method. Otherwise,
962 * returns false.
963 */
964 boolean hasWriteObjectMethod() {
965 requireInitialized();
966 return (writeObjectMethod != null);
967 }
968
969 /**
970 * Returns true if represented class is serializable (but not
971 * externalizable) and defines a conformant readObject method. Otherwise,
972 * returns false.
973 */
974 boolean hasReadObjectMethod() {
975 requireInitialized();
976 return (readObjectMethod != null);
1047 if (cause instanceof IllegalAccessException iae)
1048 throw iae;
1049 // not supposed to happen
1050 throw x;
1051 }
1052 }
1053 } catch (IllegalAccessException ex) {
1054 // should not occur, as access checks have been suppressed
1055 throw new InternalError(ex);
1056 } catch (InvocationTargetException ex) {
1057 Throwable cause = ex.getCause();
1058 if (cause instanceof Error err)
1059 throw err;
1060 else
1061 throw ex;
1062 } catch (InstantiationError err) {
1063 var ex = new InstantiationException();
1064 ex.initCause(err);
1065 throw ex;
1066 }
1067 } else {
1068 throw new UnsupportedOperationException();
1069 }
1070 }
1071
1072 /**
1073 * Invokes the writeObject method of the represented serializable class.
1074 * Throws UnsupportedOperationException if this class descriptor is not
1075 * associated with a class, or if the class is externalizable,
1076 * non-serializable or does not define writeObject.
1077 */
1078 void invokeWriteObject(Object obj, ObjectOutputStream out)
1079 throws IOException, UnsupportedOperationException
1080 {
1081 requireInitialized();
1082 if (writeObjectMethod != null) {
1083 try {
1084 writeObjectMethod.invoke(obj, new Object[]{ out });
1085 } catch (InvocationTargetException ex) {
1086 Throwable th = ex.getCause();
1087 if (th instanceof IOException) {
1088 throw (IOException) th;
1089 } else {
1090 throwMiscException(th);
1091 }
1426 ObjectStreamClass desc = new ObjectStreamClass();
1427 if (isProxy) {
1428 desc.initProxy(cl, null, superDesc);
1429 } else {
1430 desc.initNonProxy(this, cl, null, superDesc);
1431 }
1432 return desc;
1433 }
1434
1435 /**
1436 * Returns public no-arg constructor of given class, or null if none found.
1437 * Access checks are disabled on the returned constructor (if any), since
1438 * the defining class may still be non-public.
1439 */
1440 private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1441 try {
1442 Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1443 cons.setAccessible(true);
1444 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1445 cons : null;
1446 } catch (NoSuchMethodException ex) {
1447 return null;
1448 }
1449 }
1450
1451 /**
1452 * Returns subclass-accessible no-arg constructor of first non-serializable
1453 * superclass, or null if none found. Access checks are disabled on the
1454 * returned constructor (if any).
1455 */
1456 private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1457 return reflFactory.newConstructorForSerialization(cl);
1458 }
1459
1460 /**
1461 * Returns the canonical constructor for the given record class, or null if
1462 * the not found ( which should never happen for correctly generated record
1463 * classes ).
1464 */
1465 @SuppressWarnings("removal")
1466 private static MethodHandle canonicalRecordCtr(Class<?> cls) {
1919 private static final class FieldReflector {
1920
1921 /** handle for performing unsafe operations */
1922 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
1923
1924 /** fields to operate on */
1925 private final ObjectStreamField[] fields;
1926 /** number of primitive fields */
1927 private final int numPrimFields;
1928 /** unsafe field keys for reading fields - may contain dupes */
1929 private final long[] readKeys;
1930 /** unsafe fields keys for writing fields - no dupes */
1931 private final long[] writeKeys;
1932 /** field data offsets */
1933 private final int[] offsets;
1934 /** field type codes */
1935 private final char[] typeCodes;
1936 /** field types */
1937 private final Class<?>[] types;
1938
1939 /**
1940 * Constructs FieldReflector capable of setting/getting values from the
1941 * subset of fields whose ObjectStreamFields contain non-null
1942 * reflective Field objects. ObjectStreamFields with null Fields are
1943 * treated as filler, for which get operations return default values
1944 * and set operations discard given values.
1945 */
1946 FieldReflector(ObjectStreamField[] fields) {
1947 this.fields = fields;
1948 int nfields = fields.length;
1949 readKeys = new long[nfields];
1950 writeKeys = new long[nfields];
1951 offsets = new int[nfields];
1952 typeCodes = new char[nfields];
1953 ArrayList<Class<?>> typeList = new ArrayList<>();
1954 Set<Long> usedKeys = new HashSet<>();
1955
1956
1957 for (int i = 0; i < nfields; i++) {
1958 ObjectStreamField f = fields[i];
2039 case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off));
2040 default -> throw new InternalError();
2041 }
2042 }
2043 }
2044
2045 /**
2046 * Fetches the serializable object field values of object obj and
2047 * stores them in array vals starting at offset 0. The caller is
2048 * responsible for ensuring that obj is of the proper type.
2049 */
2050 void getObjFieldValues(Object obj, Object[] vals) {
2051 if (obj == null) {
2052 throw new NullPointerException();
2053 }
2054 /* assuming checkDefaultSerialize() has been called on the class
2055 * descriptor this FieldReflector was obtained from, no field keys
2056 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2057 */
2058 for (int i = numPrimFields; i < fields.length; i++) {
2059 vals[offsets[i]] = switch (typeCodes[i]) {
2060 case 'L', '[' -> UNSAFE.getReference(obj, readKeys[i]);
2061 default -> throw new InternalError();
2062 };
2063 }
2064 }
2065
2066 /**
2067 * Checks that the given values, from array vals starting at offset 0,
2068 * are assignable to the given serializable object fields.
2069 * @throws ClassCastException if any value is not assignable
2070 */
2071 void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2072 setObjFieldValues(obj, vals, true);
2073 }
2074
2075 /**
2076 * Sets the serializable object fields of object obj using values from
2077 * array vals starting at offset 0. The caller is responsible for
2078 * ensuring that obj is of the proper type; however, attempts to set a
2079 * field with a value of the wrong type will trigger an appropriate
2080 * ClassCastException.
2081 */
2082 void setObjFieldValues(Object obj, Object[] vals) {
2083 setObjFieldValues(obj, vals, false);
2084 }
2085
2086 private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2087 if (obj == null) {
2088 throw new NullPointerException();
2089 }
2090 for (int i = numPrimFields; i < fields.length; i++) {
2091 long key = writeKeys[i];
2092 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2093 continue; // discard value
2094 }
2095 switch (typeCodes[i]) {
2096 case 'L', '[' -> {
2097 Object val = vals[offsets[i]];
2098 if (val != null &&
2099 !types[i - numPrimFields].isInstance(val))
2100 {
2101 Field f = fields[i].getField();
2102 throw new ClassCastException(
2103 "cannot assign instance of " +
2104 val.getClass().getName() + " to field " +
2105 f.getDeclaringClass().getName() + "." +
2106 f.getName() + " of type " +
2107 f.getType().getName() + " in instance of " +
2108 obj.getClass().getName());
2109 }
2110 if (!dryRun)
2111 UNSAFE.putReference(obj, key, val);
2112 }
2113 default -> throw new InternalError();
2114 }
2115 }
2116 }
2117 }
2118
2119 /**
2120 * Matches given set of serializable fields with serializable fields
2121 * described by the given local class descriptor, and returns a
2122 * FieldReflector instance capable of setting/getting values from the
2123 * subset of fields that match (non-matching fields are treated as filler,
2124 * for which get operations return default values and set operations
2125 * discard given values). Throws InvalidClassException if unresolvable
2126 * type conflicts exist between the two sets of fields.
2127 */
2128 private static FieldReflector getReflector(ObjectStreamField[] fields,
2129 ObjectStreamClass localDesc)
2130 throws InvalidClassException
2131 {
|
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;
54 import java.util.Comparator;
55 import java.util.HashSet;
56 import java.util.Map;
57 import java.util.Set;
58 import java.util.concurrent.ConcurrentHashMap;
59
60 import jdk.internal.MigratedValueClass;
61 import jdk.internal.event.SerializationMisdeclarationEvent;
62 import jdk.internal.misc.Unsafe;
63 import jdk.internal.reflect.CallerSensitive;
64 import jdk.internal.reflect.Reflection;
65 import jdk.internal.reflect.ReflectionFactory;
66 import jdk.internal.access.SharedSecrets;
67 import jdk.internal.access.JavaSecurityAccess;
68 import jdk.internal.util.ByteArray;
69 import sun.reflect.misc.ReflectUtil;
70
71 /**
72 * Serialization's descriptor for classes. It contains the name and
73 * serialVersionUID of the class. The ObjectStreamClass for a specific class
74 * loaded in this Java VM can be found/created using the lookup method.
75 *
76 * <p>The algorithm to compute the SerialVersionUID is described in
77 * <a href="{@docRoot}/../specs/serialization/class.html#stream-unique-identifiers">
78 * <cite>Java Object Serialization Specification</cite>, Section 4.6, "Stream Unique Identifiers"</a>.
79 *
80 * @spec serialization/index.html Java Object Serialization Specification
81 * @author Mike Warres
82 * @author Roger Riggs
83 * @see ObjectStreamField
84 * @see <a href="{@docRoot}/../specs/serialization/class.html">
85 * <cite>Java Object Serialization Specification,</cite> Section 4, "Class Descriptors"</a>
86 * @since 1.1
87 */
88 public final class ObjectStreamClass implements Serializable {
89
90 /** serialPersistentFields value indicating no serializable fields */
91 public static final ObjectStreamField[] NO_FIELDS =
92 new ObjectStreamField[0];
93
94 @java.io.Serial
95 private static final long serialVersionUID = -6120832682080437368L;
96 /**
97 * {@code ObjectStreamClass} has no fields for default serialization.
98 */
122 @Override
123 protected Map<FieldReflectorKey, FieldReflector> computeValue(Class<?> type) {
124 return new ConcurrentHashMap<>();
125 }
126 };
127 }
128
129 /** class associated with this descriptor (if any) */
130 private Class<?> cl;
131 /** name of class represented by this descriptor */
132 private String name;
133 /** serialVersionUID of represented class (null if not computed yet) */
134 private volatile Long suid;
135
136 /** true if represents dynamic proxy class */
137 private boolean isProxy;
138 /** true if represents enum type */
139 private boolean isEnum;
140 /** true if represents record type */
141 private boolean isRecord;
142 /** true if represents a value class */
143 private boolean isValue;
144 /** true if represented class implements Serializable */
145 private boolean serializable;
146 /** true if represented class implements Externalizable */
147 private boolean externalizable;
148 /** true if desc has data written by class-defined writeObject method */
149 private boolean hasWriteObjectData;
150 /**
151 * true if desc has externalizable data written in block data format; this
152 * must be true by default to accommodate ObjectInputStream subclasses which
153 * override readClassDescriptor() to return class descriptors obtained from
154 * ObjectStreamClass.lookup() (see 4461737)
155 */
156 private boolean hasBlockExternalData = true;
157
158 /**
159 * Contains information about InvalidClassException instances to be thrown
160 * when attempting operations on an invalid class. Note that instances of
161 * this class are immutable and are potentially shared among
162 * ObjectStreamClass instances.
163 */
363 * @param all if true, return descriptors for all classes; if false, only
364 * return descriptors for serializable classes
365 */
366 static ObjectStreamClass lookup(Class<?> cl, boolean all) {
367 if (!(all || Serializable.class.isAssignableFrom(cl))) {
368 return null;
369 }
370 return Caches.localDescs.get(cl);
371 }
372
373 /**
374 * Creates local class descriptor representing given class.
375 */
376 @SuppressWarnings("removal")
377 private ObjectStreamClass(final Class<?> cl) {
378 this.cl = cl;
379 name = cl.getName();
380 isProxy = Proxy.isProxyClass(cl);
381 isEnum = Enum.class.isAssignableFrom(cl);
382 isRecord = cl.isRecord();
383 isValue = cl.isValue();
384 serializable = Serializable.class.isAssignableFrom(cl);
385 externalizable = Externalizable.class.isAssignableFrom(cl);
386
387 Class<?> superCl = cl.getSuperclass();
388 superDesc = (superCl != null) ? lookup(superCl, false) : null;
389 localDesc = this;
390
391 if (serializable) {
392 AccessController.doPrivileged(new PrivilegedAction<>() {
393 public Void run() {
394 if (isEnum) {
395 suid = 0L;
396 fields = NO_FIELDS;
397 return null;
398 }
399 if (cl.isArray()) {
400 fields = NO_FIELDS;
401 return null;
402 }
403
404 suid = getDeclaredSUID(cl);
405 try {
406 fields = getSerialFields(cl);
407 computeFieldOffsets();
408 } catch (InvalidClassException e) {
409 serializeEx = deserializeEx =
410 new ExceptionInfo(e.classname, e.getMessage());
411 fields = NO_FIELDS;
412 }
413
414 if (isRecord) {
415 canonicalCtr = canonicalRecordCtr(cl);
416 deserializationCtrs = new DeserializationConstructorsCache();
417 } else if (isValue) {
418 // Value object instance creation is specialized in newInstance()
419 cons = null;
420 } else if (externalizable) {
421 cons = getExternalizableConstructor(cl);
422 } else {
423 cons = getSerializableConstructor(cl);
424 writeObjectMethod = getPrivateMethod(cl, "writeObject",
425 new Class<?>[] { ObjectOutputStream.class },
426 Void.TYPE);
427 readObjectMethod = getPrivateMethod(cl, "readObject",
428 new Class<?>[] { ObjectInputStream.class },
429 Void.TYPE);
430 readObjectNoDataMethod = getPrivateMethod(
431 cl, "readObjectNoData", null, Void.TYPE);
432 hasWriteObjectData = (writeObjectMethod != null);
433 }
434 domains = getProtectionDomains(cons, cl);
435 writeReplaceMethod = getInheritableMethod(
436 cl, "writeReplace", null, Object.class);
437 readResolveMethod = getInheritableMethod(
438 cl, "readResolve", null, Object.class);
439 return null;
440 }
441 });
442 } else {
443 suid = 0L;
444 fields = NO_FIELDS;
445 }
446
447 try {
448 fieldRefl = getReflector(fields, this);
449 } catch (InvalidClassException ex) {
450 // field mismatches impossible when matching local fields vs. self
451 throw new InternalError(ex);
452 }
453
454 if (deserializeEx == null) {
455 if (isEnum) {
456 deserializeEx = new ExceptionInfo(name, "enum type");
457 } else if (cons == null && !(isRecord | isValue)) {
458 deserializeEx = new ExceptionInfo(name, "no valid constructor");
459 }
460 }
461 if (isRecord && canonicalCtr == null) {
462 deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
463 } else {
464 for (int i = 0; i < fields.length; i++) {
465 if (fields[i].getField() == null) {
466 defaultSerializeEx = new ExceptionInfo(
467 name, "unmatched serializable field(s) declared");
468 }
469 }
470 }
471 initialized = true;
472
473 if (SerializationMisdeclarationEvent.enabled() && serializable) {
474 SerializationMisdeclarationChecker.checkMisdeclarations(cl);
475 }
476 }
477
635 }
636
637 this.cl = cl;
638 this.resolveEx = resolveEx;
639 this.superDesc = superDesc;
640 name = model.name;
641 this.suid = suid;
642 isProxy = false;
643 isEnum = model.isEnum;
644 serializable = model.serializable;
645 externalizable = model.externalizable;
646 hasBlockExternalData = model.hasBlockExternalData;
647 hasWriteObjectData = model.hasWriteObjectData;
648 fields = model.fields;
649 primDataSize = model.primDataSize;
650 numObjFields = model.numObjFields;
651
652 if (osc != null) {
653 localDesc = osc;
654 isRecord = localDesc.isRecord;
655 isValue = localDesc.isValue;
656 // canonical record constructor is shared
657 canonicalCtr = localDesc.canonicalCtr;
658 // cache of deserialization constructors is shared
659 deserializationCtrs = localDesc.deserializationCtrs;
660 writeObjectMethod = localDesc.writeObjectMethod;
661 readObjectMethod = localDesc.readObjectMethod;
662 readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
663 writeReplaceMethod = localDesc.writeReplaceMethod;
664 readResolveMethod = localDesc.readResolveMethod;
665 if (deserializeEx == null) {
666 deserializeEx = localDesc.deserializeEx;
667 }
668 domains = localDesc.domains;
669 assert cl.isRecord() ? localDesc.cons == null : true;
670 cons = localDesc.cons;
671 }
672
673 fieldRefl = getReflector(fields, localDesc);
674 // reassign to matched fields so as to reflect local unshared settings
675 fields = fieldRefl.getFields();
917 }
918
919 /**
920 * Returns true if represented class implements Externalizable, false
921 * otherwise.
922 */
923 boolean isExternalizable() {
924 requireInitialized();
925 return externalizable;
926 }
927
928 /**
929 * Returns true if represented class implements Serializable, false
930 * otherwise.
931 */
932 boolean isSerializable() {
933 requireInitialized();
934 return serializable;
935 }
936
937 /**
938 * {@return {code true} if the class is a value class, {@code false} otherwise}
939 */
940 boolean isValue() {
941 requireInitialized();
942 return isValue;
943 }
944
945 /**
946 * Returns true if class descriptor represents externalizable class that
947 * has written its data in 1.2 (block data) format, false otherwise.
948 */
949 boolean hasBlockExternalData() {
950 requireInitialized();
951 return hasBlockExternalData;
952 }
953
954 /**
955 * Returns true if class descriptor represents serializable (but not
956 * externalizable) class which has written its data via a custom
957 * writeObject() method, false otherwise.
958 */
959 boolean hasWriteObjectData() {
960 requireInitialized();
961 return hasWriteObjectData;
962 }
963
964 /**
965 * Returns true if represented class is serializable/externalizable and can
966 * be instantiated by the serialization runtime--i.e., if it is
967 * externalizable and defines a public no-arg constructor, if it is
968 * non-externalizable and its first non-serializable superclass defines an
969 * accessible no-arg constructor, or if the class is a migrated value class.
970 * Otherwise, returns false.
971 */
972 boolean isInstantiable() {
973 requireInitialized();
974 return (cons != null |
975 (isValue && cl != null && cl.isAnnotationPresent(jdk.internal.MigratedValueClass.class)));
976 }
977
978 /**
979 * Returns true if represented class is serializable (but not
980 * externalizable) and defines a conformant writeObject method. Otherwise,
981 * returns false.
982 */
983 boolean hasWriteObjectMethod() {
984 requireInitialized();
985 return (writeObjectMethod != null);
986 }
987
988 /**
989 * Returns true if represented class is serializable (but not
990 * externalizable) and defines a conformant readObject method. Otherwise,
991 * returns false.
992 */
993 boolean hasReadObjectMethod() {
994 requireInitialized();
995 return (readObjectMethod != null);
1066 if (cause instanceof IllegalAccessException iae)
1067 throw iae;
1068 // not supposed to happen
1069 throw x;
1070 }
1071 }
1072 } catch (IllegalAccessException ex) {
1073 // should not occur, as access checks have been suppressed
1074 throw new InternalError(ex);
1075 } catch (InvocationTargetException ex) {
1076 Throwable cause = ex.getCause();
1077 if (cause instanceof Error err)
1078 throw err;
1079 else
1080 throw ex;
1081 } catch (InstantiationError err) {
1082 var ex = new InstantiationException();
1083 ex.initCause(err);
1084 throw ex;
1085 }
1086 } else if (isValue) {
1087 // Start with a buffered default value.
1088 return FieldReflector.newValueInstance(cl);
1089 } else {
1090 throw new UnsupportedOperationException();
1091 }
1092 }
1093
1094 /**
1095 * Finish the initialization of a value object.
1096 * @param obj an object (larval if a value object)
1097 * @return the finished object
1098 */
1099 Object finishValue(Object obj) {
1100 return (isValue) ? FieldReflector.finishValueInstance(obj) : obj;
1101 }
1102
1103 /**
1104 * Invokes the writeObject method of the represented serializable class.
1105 * Throws UnsupportedOperationException if this class descriptor is not
1106 * associated with a class, or if the class is externalizable,
1107 * non-serializable or does not define writeObject.
1108 */
1109 void invokeWriteObject(Object obj, ObjectOutputStream out)
1110 throws IOException, UnsupportedOperationException
1111 {
1112 requireInitialized();
1113 if (writeObjectMethod != null) {
1114 try {
1115 writeObjectMethod.invoke(obj, new Object[]{ out });
1116 } catch (InvocationTargetException ex) {
1117 Throwable th = ex.getCause();
1118 if (th instanceof IOException) {
1119 throw (IOException) th;
1120 } else {
1121 throwMiscException(th);
1122 }
1457 ObjectStreamClass desc = new ObjectStreamClass();
1458 if (isProxy) {
1459 desc.initProxy(cl, null, superDesc);
1460 } else {
1461 desc.initNonProxy(this, cl, null, superDesc);
1462 }
1463 return desc;
1464 }
1465
1466 /**
1467 * Returns public no-arg constructor of given class, or null if none found.
1468 * Access checks are disabled on the returned constructor (if any), since
1469 * the defining class may still be non-public.
1470 */
1471 private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1472 try {
1473 Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1474 cons.setAccessible(true);
1475 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1476 cons : null;
1477 } catch (NoSuchMethodException | InaccessibleObjectException ex) {
1478 return null;
1479 }
1480 }
1481
1482 /**
1483 * Returns subclass-accessible no-arg constructor of first non-serializable
1484 * superclass, or null if none found. Access checks are disabled on the
1485 * returned constructor (if any).
1486 */
1487 private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1488 return reflFactory.newConstructorForSerialization(cl);
1489 }
1490
1491 /**
1492 * Returns the canonical constructor for the given record class, or null if
1493 * the not found ( which should never happen for correctly generated record
1494 * classes ).
1495 */
1496 @SuppressWarnings("removal")
1497 private static MethodHandle canonicalRecordCtr(Class<?> cls) {
1950 private static final class FieldReflector {
1951
1952 /** handle for performing unsafe operations */
1953 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
1954
1955 /** fields to operate on */
1956 private final ObjectStreamField[] fields;
1957 /** number of primitive fields */
1958 private final int numPrimFields;
1959 /** unsafe field keys for reading fields - may contain dupes */
1960 private final long[] readKeys;
1961 /** unsafe fields keys for writing fields - no dupes */
1962 private final long[] writeKeys;
1963 /** field data offsets */
1964 private final int[] offsets;
1965 /** field type codes */
1966 private final char[] typeCodes;
1967 /** field types */
1968 private final Class<?>[] types;
1969
1970 /**
1971 * Return a new instance of the class using Unsafe.uninitializedDefaultValue
1972 * and buffer it.
1973 * @param clazz The value class
1974 * @return a buffered default value
1975 */
1976 static Object newValueInstance(Class<?> clazz) throws InstantiationException{
1977 assert clazz.isValue() : "Should be a value class";
1978 // may not be implicitly constructible; so allocate with Unsafe
1979 Object obj = UNSAFE.uninitializedDefaultValue(clazz);
1980 return UNSAFE.makePrivateBuffer(obj);
1981 }
1982
1983 /**
1984 * Finish a value object, clear the larval state and returning the value object.
1985 * @param obj a buffered value object in a larval state
1986 * @return the finished value object
1987 */
1988 static Object finishValueInstance(Object obj) {
1989 assert (obj.getClass().isValue()) : "Should be a value class";
1990 return UNSAFE.finishPrivateBuffer(obj);
1991 }
1992
1993 /**
1994 * Constructs FieldReflector capable of setting/getting values from the
1995 * subset of fields whose ObjectStreamFields contain non-null
1996 * reflective Field objects. ObjectStreamFields with null Fields are
1997 * treated as filler, for which get operations return default values
1998 * and set operations discard given values.
1999 */
2000 FieldReflector(ObjectStreamField[] fields) {
2001 this.fields = fields;
2002 int nfields = fields.length;
2003 readKeys = new long[nfields];
2004 writeKeys = new long[nfields];
2005 offsets = new int[nfields];
2006 typeCodes = new char[nfields];
2007 ArrayList<Class<?>> typeList = new ArrayList<>();
2008 Set<Long> usedKeys = new HashSet<>();
2009
2010
2011 for (int i = 0; i < nfields; i++) {
2012 ObjectStreamField f = fields[i];
2093 case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off));
2094 default -> throw new InternalError();
2095 }
2096 }
2097 }
2098
2099 /**
2100 * Fetches the serializable object field values of object obj and
2101 * stores them in array vals starting at offset 0. The caller is
2102 * responsible for ensuring that obj is of the proper type.
2103 */
2104 void getObjFieldValues(Object obj, Object[] vals) {
2105 if (obj == null) {
2106 throw new NullPointerException();
2107 }
2108 /* assuming checkDefaultSerialize() has been called on the class
2109 * descriptor this FieldReflector was obtained from, no field keys
2110 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2111 */
2112 for (int i = numPrimFields; i < fields.length; i++) {
2113 Field f = fields[i].getField();
2114 vals[offsets[i]] = switch (typeCodes[i]) {
2115 case 'L', '[' ->
2116 UNSAFE.isFlatField(f)
2117 ? UNSAFE.getValue(obj, readKeys[i], f.getType())
2118 : UNSAFE.getReference(obj, readKeys[i]);
2119 default -> throw new InternalError();
2120 };
2121 }
2122 }
2123
2124 /**
2125 * Checks that the given values, from array vals starting at offset 0,
2126 * are assignable to the given serializable object fields.
2127 * @throws ClassCastException if any value is not assignable
2128 */
2129 void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2130 setObjFieldValues(obj, vals, true);
2131 }
2132
2133 /**
2134 * Sets the serializable object fields of object obj using values from
2135 * array vals starting at offset 0. The caller is responsible for
2136 * ensuring that obj is of the proper type; however, attempts to set a
2137 * field with a value of the wrong type will trigger an appropriate
2138 * ClassCastException.
2139 */
2140 void setObjFieldValues(Object obj, Object[] vals) {
2141 setObjFieldValues(obj, vals, false);
2142 }
2143
2144 private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2145 if (obj == null) {
2146 throw new NullPointerException();
2147 }
2148 for (int i = numPrimFields; i < fields.length; i++) {
2149 long key = writeKeys[i];
2150 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2151 continue; // discard value
2152 }
2153 switch (typeCodes[i]) {
2154 case 'L', '[' -> {
2155 Field f = fields[i].getField();
2156 Object val = vals[offsets[i]];
2157 if (val != null &&
2158 !types[i - numPrimFields].isInstance(val))
2159 {
2160 throw new ClassCastException(
2161 "cannot assign instance of " +
2162 val.getClass().getName() + " to field " +
2163 f.getDeclaringClass().getName() + "." +
2164 f.getName() + " of type " +
2165 f.getType().getName() + " in instance of " +
2166 obj.getClass().getName());
2167 }
2168 if (!dryRun) {
2169 if (UNSAFE.isFlatField(f)) {
2170 UNSAFE.putValue(obj, key, f.getType(), val);
2171 } else {
2172 UNSAFE.putReference(obj, key, val);
2173 }
2174 }
2175 }
2176 default -> throw new InternalError();
2177 }
2178 }
2179 }
2180 }
2181
2182 /**
2183 * Matches given set of serializable fields with serializable fields
2184 * described by the given local class descriptor, and returns a
2185 * FieldReflector instance capable of setting/getting values from the
2186 * subset of fields that match (non-matching fields are treated as filler,
2187 * for which get operations return default values and set operations
2188 * discard given values). Throws InvalidClassException if unresolvable
2189 * type conflicts exist between the two sets of fields.
2190 */
2191 private static FieldReflector getReflector(ObjectStreamField[] fields,
2192 ObjectStreamClass localDesc)
2193 throws InvalidClassException
2194 {
|