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