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