1 /*
2 * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
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.ref.Reference;
31 import java.lang.ref.ReferenceQueue;
32 import java.lang.ref.SoftReference;
33 import java.lang.ref.WeakReference;
34 import java.lang.reflect.Constructor;
35 import java.lang.reflect.Field;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.RecordComponent;
38 import java.lang.reflect.UndeclaredThrowableException;
39 import java.lang.reflect.Member;
40 import java.lang.reflect.Method;
41 import java.lang.reflect.Modifier;
42 import java.lang.reflect.Proxy;
43 import java.security.AccessControlContext;
44 import java.security.AccessController;
45 import java.security.MessageDigest;
46 import java.security.NoSuchAlgorithmException;
47 import java.security.PermissionCollection;
48 import java.security.Permissions;
49 import java.security.PrivilegedAction;
50 import java.security.PrivilegedActionException;
51 import java.security.PrivilegedExceptionAction;
52 import java.security.ProtectionDomain;
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.Collections;
56 import java.util.Comparator;
57 import java.util.HashSet;
58 import java.util.Set;
59 import java.util.concurrent.ConcurrentHashMap;
60 import java.util.concurrent.ConcurrentMap;
61 import jdk.internal.misc.Unsafe;
62 import jdk.internal.reflect.CallerSensitive;
63 import jdk.internal.reflect.Reflection;
64 import jdk.internal.reflect.ReflectionFactory;
65 import jdk.internal.access.SharedSecrets;
66 import jdk.internal.access.JavaSecurityAccess;
67 import sun.reflect.misc.ReflectUtil;
68 import static java.io.ObjectStreamField.*;
69
70 /**
71 * Serialization's descriptor for classes. It contains the name and
72 * serialVersionUID of the class. The ObjectStreamClass for a specific class
73 * loaded in this Java VM can be found/created using the lookup method.
74 *
75 * <p>The algorithm to compute the SerialVersionUID is described in
76 * <a href="{@docRoot}/../specs/serialization/class.html#stream-unique-identifiers">
77 * Object Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
78 *
79 * @author Mike Warres
80 * @author Roger Riggs
81 * @see ObjectStreamField
82 * @see <a href="{@docRoot}/../specs/serialization/class.html">
83 * Object Serialization Specification, Section 4, Class Descriptors</a>
84 * @since 1.1
85 */
86 public 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 @java.io.Serial
95 private static final ObjectStreamField[] serialPersistentFields =
96 NO_FIELDS;
97
98 /** reflection factory for obtaining serialization constructors */
99 private static final ReflectionFactory reflFactory =
100 AccessController.doPrivileged(
101 new ReflectionFactory.GetReflectionFactoryAction());
102
103 private static class Caches {
104 /** cache mapping local classes -> descriptors */
105 static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs =
106 new ConcurrentHashMap<>();
107
108 /** cache mapping field group/local desc pairs -> field reflectors */
109 static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors =
110 new ConcurrentHashMap<>();
111
112 /** queue for WeakReferences to local classes */
113 private static final ReferenceQueue<Class<?>> localDescsQueue =
114 new ReferenceQueue<>();
115 /** queue for WeakReferences to field reflectors keys */
116 private static final ReferenceQueue<Class<?>> reflectorsQueue =
117 new ReferenceQueue<>();
118 }
119
120 /** class associated with this descriptor (if any) */
121 private Class<?> cl;
122 /** name of class represented by this descriptor */
123 private String name;
124 /** serialVersionUID of represented class (null if not computed yet) */
125 private volatile Long suid;
126
127 /** true if represents dynamic proxy class */
128 private boolean isProxy;
129 /** true if represents enum type */
130 private boolean isEnum;
131 /** true if represents record type */
132 private boolean isRecord;
133 /** true if represented class implements Serializable */
134 private boolean serializable;
135 /** true if represented class implements Externalizable */
136 private boolean externalizable;
137 /** true if desc has data written by class-defined writeObject method */
138 private boolean hasWriteObjectData;
139 /**
140 * true if desc has externalizable data written in block data format; this
141 * must be true by default to accommodate ObjectInputStream subclasses which
142 * override readClassDescriptor() to return class descriptors obtained from
143 * ObjectStreamClass.lookup() (see 4461737)
144 */
145 private boolean hasBlockExternalData = true;
146
147 /**
148 * Contains information about InvalidClassException instances to be thrown
149 * when attempting operations on an invalid class. Note that instances of
150 * this class are immutable and are potentially shared among
151 * ObjectStreamClass instances.
152 */
153 private static class ExceptionInfo {
154 private final String className;
155 private final String message;
156
157 ExceptionInfo(String cn, String msg) {
158 className = cn;
159 message = msg;
160 }
161
162 /**
163 * Returns (does not throw) an InvalidClassException instance created
164 * from the information in this object, suitable for being thrown by
165 * the caller.
166 */
167 InvalidClassException newInvalidClassException() {
168 return new InvalidClassException(className, message);
169 }
170 }
171
172 /** exception (if any) thrown while attempting to resolve class */
173 private ClassNotFoundException resolveEx;
174 /** exception (if any) to throw if non-enum deserialization attempted */
175 private ExceptionInfo deserializeEx;
176 /** exception (if any) to throw if non-enum serialization attempted */
177 private ExceptionInfo serializeEx;
178 /** exception (if any) to throw if default serialization attempted */
179 private ExceptionInfo defaultSerializeEx;
180
181 /** serializable fields */
182 private ObjectStreamField[] fields;
183 /** aggregate marshalled size of primitive fields */
184 private int primDataSize;
185 /** number of non-primitive fields */
186 private int numObjFields;
187 /** reflector for setting/getting serializable field values */
188 private FieldReflector fieldRefl;
189 /** data layout of serialized objects described by this class desc */
190 private volatile ClassDataSlot[] dataLayout;
191
192 /** serialization-appropriate constructor, or null if none */
193 private Constructor<?> cons;
194 /** record canonical constructor, or null */
195 private MethodHandle canonicalCtr;
196 /** protection domains that need to be checked when calling the constructor */
197 private ProtectionDomain[] domains;
198
199 /** class-defined writeObject method, or null if none */
200 private Method writeObjectMethod;
201 /** class-defined readObject method, or null if none */
202 private Method readObjectMethod;
203 /** class-defined readObjectNoData method, or null if none */
204 private Method readObjectNoDataMethod;
205 /** class-defined writeReplace method, or null if none */
206 private Method writeReplaceMethod;
207 /** class-defined readResolve method, or null if none */
208 private Method readResolveMethod;
209
210 /** local class descriptor for represented class (may point to self) */
211 private ObjectStreamClass localDesc;
212 /** superclass descriptor appearing in stream */
213 private ObjectStreamClass superDesc;
214
215 /** true if, and only if, the object has been correctly initialized */
216 private boolean initialized;
217
218 /**
219 * Initializes native code.
220 */
221 private static native void initNative();
222 static {
223 initNative();
224 }
225
226 /**
227 * Find the descriptor for a class that can be serialized. Creates an
228 * ObjectStreamClass instance if one does not exist yet for class. Null is
229 * returned if the specified class does not implement java.io.Serializable
230 * or java.io.Externalizable.
231 *
232 * @param cl class for which to get the descriptor
233 * @return the class descriptor for the specified class
234 */
235 public static ObjectStreamClass lookup(Class<?> cl) {
236 return lookup(cl, false);
237 }
238
239 /**
240 * Returns the descriptor for any class, regardless of whether it
241 * implements {@link Serializable}.
242 *
243 * @param cl class for which to get the descriptor
244 * @return the class descriptor for the specified class
245 * @since 1.6
246 */
247 public static ObjectStreamClass lookupAny(Class<?> cl) {
248 return lookup(cl, true);
249 }
250
251 /**
252 * Returns the name of the class described by this descriptor.
253 * This method returns the name of the class in the format that
254 * is used by the {@link Class#getName} method.
255 *
256 * @return a string representing the name of the class
257 */
258 public String getName() {
259 return name;
260 }
261
262 /**
263 * Return the serialVersionUID for this class. The serialVersionUID
264 * defines a set of classes all with the same name that have evolved from a
265 * common root class and agree to be serialized and deserialized using a
266 * common format. NonSerializable classes have a serialVersionUID of 0L.
267 *
268 * @return the SUID of the class described by this descriptor
269 */
270 public long getSerialVersionUID() {
271 // REMIND: synchronize instead of relying on volatile?
272 if (suid == null) {
273 if (isRecord)
274 return 0L;
275
276 suid = AccessController.doPrivileged(
277 new PrivilegedAction<Long>() {
278 public Long run() {
279 return computeDefaultSUID(cl);
280 }
281 }
282 );
283 }
284 return suid.longValue();
285 }
286
287 /**
288 * Return the class in the local VM that this version is mapped to. Null
289 * is returned if there is no corresponding local class.
290 *
291 * @return the {@code Class} instance that this descriptor represents
292 */
293 @CallerSensitive
294 public Class<?> forClass() {
295 if (cl == null) {
296 return null;
297 }
298 requireInitialized();
299 if (System.getSecurityManager() != null) {
300 Class<?> caller = Reflection.getCallerClass();
301 if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) {
302 ReflectUtil.checkPackageAccess(cl);
303 }
304 }
305 return cl;
306 }
307
308 /**
309 * Return an array of the fields of this serializable class.
310 *
311 * @return an array containing an element for each persistent field of
312 * this class. Returns an array of length zero if there are no
313 * fields.
314 * @since 1.2
315 */
316 public ObjectStreamField[] getFields() {
317 return getFields(true);
318 }
319
320 /**
321 * Get the field of this class by name.
322 *
323 * @param name the name of the data field to look for
324 * @return The ObjectStreamField object of the named field or null if
325 * there is no such named field.
326 */
327 public ObjectStreamField getField(String name) {
328 return getField(name, null);
329 }
330
331 /**
332 * Return a string describing this ObjectStreamClass.
333 */
334 public String toString() {
335 return name + ": static final long serialVersionUID = " +
336 getSerialVersionUID() + "L;";
337 }
338
339 /**
340 * Looks up and returns class descriptor for given class, or null if class
341 * is non-serializable and "all" is set to false.
342 *
343 * @param cl class to look up
344 * @param all if true, return descriptors for all classes; if false, only
345 * return descriptors for serializable classes
346 */
347 static ObjectStreamClass lookup(Class<?> cl, boolean all) {
348 if (!(all || Serializable.class.isAssignableFrom(cl))) {
349 return null;
350 }
351 processQueue(Caches.localDescsQueue, Caches.localDescs);
352 WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
353 Reference<?> ref = Caches.localDescs.get(key);
354 Object entry = null;
355 if (ref != null) {
356 entry = ref.get();
357 }
358 EntryFuture future = null;
359 if (entry == null) {
360 EntryFuture newEntry = new EntryFuture();
361 Reference<?> newRef = new SoftReference<>(newEntry);
362 do {
363 if (ref != null) {
364 Caches.localDescs.remove(key, ref);
365 }
366 ref = Caches.localDescs.putIfAbsent(key, newRef);
367 if (ref != null) {
368 entry = ref.get();
369 }
370 } while (ref != null && entry == null);
371 if (entry == null) {
372 future = newEntry;
373 }
374 }
375
376 if (entry instanceof ObjectStreamClass) { // check common case first
377 return (ObjectStreamClass) entry;
378 }
379 if (entry instanceof EntryFuture) {
380 future = (EntryFuture) entry;
381 if (future.getOwner() == Thread.currentThread()) {
382 /*
383 * Handle nested call situation described by 4803747: waiting
384 * for future value to be set by a lookup() call further up the
385 * stack will result in deadlock, so calculate and set the
386 * future value here instead.
387 */
388 entry = null;
389 } else {
390 entry = future.get();
391 }
392 }
393 if (entry == null) {
394 try {
395 entry = new ObjectStreamClass(cl);
396 } catch (Throwable th) {
397 entry = th;
398 }
399 if (future.set(entry)) {
400 Caches.localDescs.put(key, new SoftReference<>(entry));
401 } else {
402 // nested lookup call already set future
403 entry = future.get();
404 }
405 }
406
407 if (entry instanceof ObjectStreamClass) {
408 return (ObjectStreamClass) entry;
409 } else if (entry instanceof RuntimeException) {
410 throw (RuntimeException) entry;
411 } else if (entry instanceof Error) {
412 throw (Error) entry;
413 } else {
414 throw new InternalError("unexpected entry: " + entry);
415 }
416 }
417
418 /**
419 * Placeholder used in class descriptor and field reflector lookup tables
420 * for an entry in the process of being initialized. (Internal) callers
421 * which receive an EntryFuture belonging to another thread as the result
422 * of a lookup should call the get() method of the EntryFuture; this will
423 * return the actual entry once it is ready for use and has been set(). To
424 * conserve objects, EntryFutures synchronize on themselves.
425 */
426 private static class EntryFuture {
427
428 private static final Object unset = new Object();
429 private final Thread owner = Thread.currentThread();
430 private Object entry = unset;
431
432 /**
433 * Attempts to set the value contained by this EntryFuture. If the
434 * EntryFuture's value has not been set already, then the value is
435 * saved, any callers blocked in the get() method are notified, and
436 * true is returned. If the value has already been set, then no saving
437 * or notification occurs, and false is returned.
438 */
439 synchronized boolean set(Object entry) {
440 if (this.entry != unset) {
441 return false;
442 }
443 this.entry = entry;
444 notifyAll();
445 return true;
446 }
447
448 /**
449 * Returns the value contained by this EntryFuture, blocking if
450 * necessary until a value is set.
451 */
452 synchronized Object get() {
453 boolean interrupted = false;
454 while (entry == unset) {
455 try {
456 wait();
457 } catch (InterruptedException ex) {
458 interrupted = true;
459 }
460 }
461 if (interrupted) {
462 AccessController.doPrivileged(
463 new PrivilegedAction<>() {
464 public Void run() {
465 Thread.currentThread().interrupt();
466 return null;
467 }
468 }
469 );
470 }
471 return entry;
472 }
473
474 /**
475 * Returns the thread that created this EntryFuture.
476 */
477 Thread getOwner() {
478 return owner;
479 }
480 }
481
482 @SuppressWarnings("preview")
483 private static boolean isRecord(Class<?> cls) {
484 return cls.isRecord();
485 }
486
487 /**
488 * Creates local class descriptor representing given class.
489 */
490 private ObjectStreamClass(final Class<?> cl) {
491 this.cl = cl;
492 name = cl.getName();
493 isProxy = Proxy.isProxyClass(cl);
494 isEnum = Enum.class.isAssignableFrom(cl);
495 isRecord = isRecord(cl);
496 serializable = Serializable.class.isAssignableFrom(cl);
497 externalizable = Externalizable.class.isAssignableFrom(cl);
498
499 Class<?> superCl = cl.getSuperclass();
500 superDesc = (superCl != null) ? lookup(superCl, false) : null;
501 localDesc = this;
502
503 if (serializable) {
504 AccessController.doPrivileged(new PrivilegedAction<>() {
505 public Void run() {
506 if (isEnum) {
507 suid = Long.valueOf(0);
508 fields = NO_FIELDS;
509 return null;
510 }
511 if (cl.isArray()) {
512 fields = NO_FIELDS;
513 return null;
514 }
515
516 suid = getDeclaredSUID(cl);
517 try {
518 fields = getSerialFields(cl);
519 computeFieldOffsets();
520 } catch (InvalidClassException e) {
521 serializeEx = deserializeEx =
522 new ExceptionInfo(e.classname, e.getMessage());
523 fields = NO_FIELDS;
524 }
525
526 if (isRecord) {
527 canonicalCtr = canonicalRecordCtr(cl);
528 } else if (externalizable) {
529 cons = getExternalizableConstructor(cl);
530 } else {
531 cons = getSerializableConstructor(cl);
532 writeObjectMethod = getPrivateMethod(cl, "writeObject",
533 new Class<?>[] { ObjectOutputStream.class },
534 Void.TYPE);
535 readObjectMethod = getPrivateMethod(cl, "readObject",
536 new Class<?>[] { ObjectInputStream.class },
537 Void.TYPE);
538 readObjectNoDataMethod = getPrivateMethod(
539 cl, "readObjectNoData", null, Void.TYPE);
540 hasWriteObjectData = (writeObjectMethod != null);
541 }
542 domains = getProtectionDomains(cons, cl);
543 writeReplaceMethod = getInheritableMethod(
544 cl, "writeReplace", null, Object.class);
545 readResolveMethod = getInheritableMethod(
546 cl, "readResolve", null, Object.class);
547 return null;
548 }
549 });
550 } else {
551 suid = Long.valueOf(0);
552 fields = NO_FIELDS;
553 }
554
555 try {
556 fieldRefl = getReflector(fields, this);
557 } catch (InvalidClassException ex) {
558 // field mismatches impossible when matching local fields vs. self
559 throw new InternalError(ex);
560 }
561
562 if (deserializeEx == null) {
563 if (isEnum) {
564 deserializeEx = new ExceptionInfo(name, "enum type");
565 } else if (cons == null && !isRecord) {
566 deserializeEx = new ExceptionInfo(name, "no valid constructor");
567 }
568 }
569 if (isRecord && canonicalCtr == null) {
570 deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
571 } else {
572 for (int i = 0; i < fields.length; i++) {
573 if (fields[i].getField() == null) {
574 defaultSerializeEx = new ExceptionInfo(
575 name, "unmatched serializable field(s) declared");
576 }
577 }
578 }
579 initialized = true;
580 }
581
582 /**
583 * Creates blank class descriptor which should be initialized via a
584 * subsequent call to initProxy(), initNonProxy() or readNonProxy().
585 */
586 ObjectStreamClass() {
587 }
588
589 /**
590 * Creates a PermissionDomain that grants no permission.
591 */
592 private ProtectionDomain noPermissionsDomain() {
593 PermissionCollection perms = new Permissions();
594 perms.setReadOnly();
595 return new ProtectionDomain(null, perms);
596 }
597
598 /**
599 * Aggregate the ProtectionDomains of all the classes that separate
600 * a concrete class {@code cl} from its ancestor's class declaring
601 * a constructor {@code cons}.
602 *
603 * If {@code cl} is defined by the boot loader, or the constructor
604 * {@code cons} is declared by {@code cl}, or if there is no security
605 * manager, then this method does nothing and {@code null} is returned.
606 *
607 * @param cons A constructor declared by {@code cl} or one of its
608 * ancestors.
609 * @param cl A concrete class, which is either the class declaring
610 * the constructor {@code cons}, or a serializable subclass
611 * of that class.
612 * @return An array of ProtectionDomain representing the set of
613 * ProtectionDomain that separate the concrete class {@code cl}
614 * from its ancestor's declaring {@code cons}, or {@code null}.
615 */
616 private ProtectionDomain[] getProtectionDomains(Constructor<?> cons,
617 Class<?> cl) {
618 ProtectionDomain[] domains = null;
619 if (cons != null && cl.getClassLoader() != null
620 && System.getSecurityManager() != null) {
621 Class<?> cls = cl;
622 Class<?> fnscl = cons.getDeclaringClass();
623 Set<ProtectionDomain> pds = null;
624 while (cls != fnscl) {
625 ProtectionDomain pd = cls.getProtectionDomain();
626 if (pd != null) {
627 if (pds == null) pds = new HashSet<>();
628 pds.add(pd);
629 }
630 cls = cls.getSuperclass();
631 if (cls == null) {
632 // that's not supposed to happen
633 // make a ProtectionDomain with no permission.
634 // should we throw instead?
635 if (pds == null) pds = new HashSet<>();
636 else pds.clear();
637 pds.add(noPermissionsDomain());
638 break;
639 }
640 }
641 if (pds != null) {
642 domains = pds.toArray(new ProtectionDomain[0]);
643 }
644 }
645 return domains;
646 }
647
648 /**
649 * Initializes class descriptor representing a proxy class.
650 */
651 void initProxy(Class<?> cl,
652 ClassNotFoundException resolveEx,
653 ObjectStreamClass superDesc)
654 throws InvalidClassException
655 {
656 ObjectStreamClass osc = null;
657 if (cl != null) {
658 osc = lookup(cl, true);
659 if (!osc.isProxy) {
660 throw new InvalidClassException(
661 "cannot bind proxy descriptor to a non-proxy class");
662 }
663 }
664 this.cl = cl;
665 this.resolveEx = resolveEx;
666 this.superDesc = superDesc;
667 isProxy = true;
668 serializable = true;
669 suid = Long.valueOf(0);
670 fields = NO_FIELDS;
671 if (osc != null) {
672 localDesc = osc;
673 name = localDesc.name;
674 externalizable = localDesc.externalizable;
675 writeReplaceMethod = localDesc.writeReplaceMethod;
676 readResolveMethod = localDesc.readResolveMethod;
677 deserializeEx = localDesc.deserializeEx;
678 domains = localDesc.domains;
679 cons = localDesc.cons;
680 }
681 fieldRefl = getReflector(fields, localDesc);
682 initialized = true;
683 }
684
685 /**
686 * Initializes class descriptor representing a non-proxy class.
687 */
688 void initNonProxy(ObjectStreamClass model,
689 Class<?> cl,
690 ClassNotFoundException resolveEx,
691 ObjectStreamClass superDesc)
692 throws InvalidClassException
693 {
694 long suid = Long.valueOf(model.getSerialVersionUID());
695 ObjectStreamClass osc = null;
696 if (cl != null) {
697 osc = lookup(cl, true);
698 if (osc.isProxy) {
699 throw new InvalidClassException(
700 "cannot bind non-proxy descriptor to a proxy class");
701 }
702 if (model.isEnum != osc.isEnum) {
703 throw new InvalidClassException(model.isEnum ?
704 "cannot bind enum descriptor to a non-enum class" :
705 "cannot bind non-enum descriptor to an enum class");
706 }
707
708 if (model.serializable == osc.serializable &&
709 !cl.isArray() && !isRecord(cl) &&
710 suid != osc.getSerialVersionUID()) {
711 throw new InvalidClassException(osc.name,
712 "local class incompatible: " +
713 "stream classdesc serialVersionUID = " + suid +
714 ", local class serialVersionUID = " +
715 osc.getSerialVersionUID());
716 }
717
718 if (!classNamesEqual(model.name, osc.name)) {
719 throw new InvalidClassException(osc.name,
720 "local class name incompatible with stream class " +
721 "name \"" + model.name + "\"");
722 }
723
724 if (!model.isEnum) {
725 if ((model.serializable == osc.serializable) &&
726 (model.externalizable != osc.externalizable)) {
727 throw new InvalidClassException(osc.name,
728 "Serializable incompatible with Externalizable");
729 }
730
731 if ((model.serializable != osc.serializable) ||
732 (model.externalizable != osc.externalizable) ||
733 !(model.serializable || model.externalizable)) {
734 deserializeEx = new ExceptionInfo(
735 osc.name, "class invalid for deserialization");
736 }
737 }
738 }
739
740 this.cl = cl;
741 if (cl != null) {
742 this.isRecord = isRecord(cl);
743 this.canonicalCtr = osc.canonicalCtr;
744 }
745 this.resolveEx = resolveEx;
746 this.superDesc = superDesc;
747 name = model.name;
748 this.suid = suid;
749 isProxy = false;
750 isEnum = model.isEnum;
751 serializable = model.serializable;
752 externalizable = model.externalizable;
753 hasBlockExternalData = model.hasBlockExternalData;
754 hasWriteObjectData = model.hasWriteObjectData;
755 fields = model.fields;
756 primDataSize = model.primDataSize;
757 numObjFields = model.numObjFields;
758
759 if (osc != null) {
760 localDesc = osc;
761 writeObjectMethod = localDesc.writeObjectMethod;
762 readObjectMethod = localDesc.readObjectMethod;
763 readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
764 writeReplaceMethod = localDesc.writeReplaceMethod;
765 readResolveMethod = localDesc.readResolveMethod;
766 if (deserializeEx == null) {
767 deserializeEx = localDesc.deserializeEx;
768 }
769 domains = localDesc.domains;
770 assert isRecord(cl) ? localDesc.cons == null : true;
771 cons = localDesc.cons;
772 }
773
774 fieldRefl = getReflector(fields, localDesc);
775 // reassign to matched fields so as to reflect local unshared settings
776 fields = fieldRefl.getFields();
777
778 initialized = true;
779 }
780
781 /**
782 * Reads non-proxy class descriptor information from given input stream.
783 * The resulting class descriptor is not fully functional; it can only be
784 * used as input to the ObjectInputStream.resolveClass() and
785 * ObjectStreamClass.initNonProxy() methods.
786 */
787 void readNonProxy(ObjectInputStream in)
788 throws IOException, ClassNotFoundException
789 {
790 name = in.readUTF();
791 suid = Long.valueOf(in.readLong());
792 isProxy = false;
793
794 byte flags = in.readByte();
795 hasWriteObjectData =
796 ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
797 hasBlockExternalData =
798 ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
799 externalizable =
800 ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
801 boolean sflag =
802 ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
803 if (externalizable && sflag) {
804 throw new InvalidClassException(
805 name, "serializable and externalizable flags conflict");
806 }
807 serializable = externalizable || sflag;
808 isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
809 if (isEnum && suid.longValue() != 0L) {
810 throw new InvalidClassException(name,
811 "enum descriptor has non-zero serialVersionUID: " + suid);
812 }
813
814 int numFields = in.readShort();
815 if (isEnum && numFields != 0) {
816 throw new InvalidClassException(name,
817 "enum descriptor has non-zero field count: " + numFields);
818 }
819 fields = (numFields > 0) ?
820 new ObjectStreamField[numFields] : NO_FIELDS;
821 for (int i = 0; i < numFields; i++) {
822 char tcode = (char) in.readByte();
823 String fname = in.readUTF();
824 String signature = ((tcode == 'L') || (tcode == '[')) ?
825 in.readTypeString() : new String(new char[] { tcode });
826 try {
827 fields[i] = new ObjectStreamField(fname, signature, false);
828 } catch (RuntimeException e) {
829 throw (IOException) new InvalidClassException(name,
830 "invalid descriptor for field " + fname).initCause(e);
831 }
832 }
833 computeFieldOffsets();
834 }
835
836 /**
837 * Writes non-proxy class descriptor information to given output stream.
838 */
839 void writeNonProxy(ObjectOutputStream out) throws IOException {
840 out.writeUTF(name);
841 out.writeLong(getSerialVersionUID());
842
843 byte flags = 0;
844 if (externalizable) {
845 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
846 int protocol = out.getProtocolVersion();
847 if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
848 flags |= ObjectStreamConstants.SC_BLOCK_DATA;
849 }
850 } else if (serializable) {
851 flags |= ObjectStreamConstants.SC_SERIALIZABLE;
852 }
853 if (hasWriteObjectData) {
854 flags |= ObjectStreamConstants.SC_WRITE_METHOD;
855 }
856 if (isEnum) {
857 flags |= ObjectStreamConstants.SC_ENUM;
858 }
859 out.writeByte(flags);
860
861 out.writeShort(fields.length);
862 for (int i = 0; i < fields.length; i++) {
863 ObjectStreamField f = fields[i];
864 out.writeByte(f.getTypeCode());
865 out.writeUTF(f.getName());
866 if (!f.isPrimitive()) {
867 out.writeTypeString(f.getTypeString());
868 }
869 }
870 }
871
872 /**
873 * Returns ClassNotFoundException (if any) thrown while attempting to
874 * resolve local class corresponding to this class descriptor.
875 */
876 ClassNotFoundException getResolveException() {
877 return resolveEx;
878 }
879
880 /**
881 * Throws InternalError if not initialized.
882 */
883 private final void requireInitialized() {
884 if (!initialized)
885 throw new InternalError("Unexpected call when not initialized");
886 }
887
888 /**
889 * Throws InvalidClassException if not initialized.
890 * To be called in cases where an uninitialized class descriptor indicates
891 * a problem in the serialization stream.
892 */
893 final void checkInitialized() throws InvalidClassException {
894 if (!initialized) {
895 throw new InvalidClassException("Class descriptor should be initialized");
896 }
897 }
898
899 /**
900 * Throws an InvalidClassException if object instances referencing this
901 * class descriptor should not be allowed to deserialize. This method does
902 * not apply to deserialization of enum constants.
903 */
904 void checkDeserialize() throws InvalidClassException {
905 requireInitialized();
906 if (deserializeEx != null) {
907 throw deserializeEx.newInvalidClassException();
908 }
909 }
910
911 /**
912 * Throws an InvalidClassException if objects whose class is represented by
913 * this descriptor should not be allowed to serialize. This method does
914 * not apply to serialization of enum constants.
915 */
916 void checkSerialize() throws InvalidClassException {
917 requireInitialized();
918 if (serializeEx != null) {
919 throw serializeEx.newInvalidClassException();
920 }
921 }
922
923 /**
924 * Throws an InvalidClassException if objects whose class is represented by
925 * this descriptor should not be permitted to use default serialization
926 * (e.g., if the class declares serializable fields that do not correspond
927 * to actual fields, and hence must use the GetField API). This method
928 * does not apply to deserialization of enum constants.
929 */
930 void checkDefaultSerialize() throws InvalidClassException {
931 requireInitialized();
932 if (defaultSerializeEx != null) {
933 throw defaultSerializeEx.newInvalidClassException();
934 }
935 }
936
937 /**
938 * Returns superclass descriptor. Note that on the receiving side, the
939 * superclass descriptor may be bound to a class that is not a superclass
940 * of the subclass descriptor's bound class.
941 */
942 ObjectStreamClass getSuperDesc() {
943 requireInitialized();
944 return superDesc;
945 }
946
947 /**
948 * Returns the "local" class descriptor for the class associated with this
949 * class descriptor (i.e., the result of
950 * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
951 * associated with this descriptor.
952 */
953 ObjectStreamClass getLocalDesc() {
954 requireInitialized();
955 return localDesc;
956 }
957
958 /**
959 * Returns arrays of ObjectStreamFields representing the serializable
960 * fields of the represented class. If copy is true, a clone of this class
961 * descriptor's field array is returned, otherwise the array itself is
962 * returned.
963 */
964 ObjectStreamField[] getFields(boolean copy) {
965 return copy ? fields.clone() : fields;
966 }
967
968 /**
969 * Looks up a serializable field of the represented class by name and type.
970 * A specified type of null matches all types, Object.class matches all
971 * non-primitive types, and any other non-null type matches assignable
972 * types only. Returns matching field, or null if no match found.
973 */
974 ObjectStreamField getField(String name, Class<?> type) {
975 for (int i = 0; i < fields.length; i++) {
976 ObjectStreamField f = fields[i];
977 if (f.getName().equals(name)) {
978 if (type == null ||
979 (type == Object.class && !f.isPrimitive()))
980 {
981 return f;
982 }
983 Class<?> ftype = f.getType();
984 if (ftype != null && type.isAssignableFrom(ftype)) {
985 return f;
986 }
987 }
988 }
989 return null;
990 }
991
992 /**
993 * Returns true if class descriptor represents a dynamic proxy class, false
994 * otherwise.
995 */
996 boolean isProxy() {
997 requireInitialized();
998 return isProxy;
999 }
1000
1001 /**
1002 * Returns true if class descriptor represents an enum type, false
1003 * otherwise.
1004 */
1005 boolean isEnum() {
1006 requireInitialized();
1007 return isEnum;
1008 }
1009
1010 /**
1011 * Returns true if class descriptor represents a record type, false
1012 * otherwise.
1013 */
1014 boolean isRecord() {
1015 requireInitialized();
1016 return isRecord;
1017 }
1018
1019 /**
1020 * Returns true if represented class implements Externalizable, false
1021 * otherwise.
1022 */
1023 boolean isExternalizable() {
1024 requireInitialized();
1025 return externalizable;
1026 }
1027
1028 /**
1029 * Returns true if represented class implements Serializable, false
1030 * otherwise.
1031 */
1032 boolean isSerializable() {
1033 requireInitialized();
1034 return serializable;
1035 }
1036
1037 /**
1038 * Returns true if class descriptor represents externalizable class that
1039 * has written its data in 1.2 (block data) format, false otherwise.
1040 */
1041 boolean hasBlockExternalData() {
1042 requireInitialized();
1043 return hasBlockExternalData;
1044 }
1045
1046 /**
1047 * Returns true if class descriptor represents serializable (but not
1048 * externalizable) class which has written its data via a custom
1049 * writeObject() method, false otherwise.
1050 */
1051 boolean hasWriteObjectData() {
1052 requireInitialized();
1053 return hasWriteObjectData;
1054 }
1055
1056 /**
1057 * Returns true if represented class is serializable/externalizable and can
1058 * be instantiated by the serialization runtime--i.e., if it is
1059 * externalizable and defines a public no-arg constructor, or if it is
1060 * non-externalizable and its first non-serializable superclass defines an
1061 * accessible no-arg constructor. Otherwise, returns false.
1062 */
1063 boolean isInstantiable() {
1064 requireInitialized();
1065 return (cons != null);
1066 }
1067
1068 /**
1069 * Returns true if represented class is serializable (but not
1070 * externalizable) and defines a conformant writeObject method. Otherwise,
1071 * returns false.
1072 */
1073 boolean hasWriteObjectMethod() {
1074 requireInitialized();
1075 return (writeObjectMethod != null);
1076 }
1077
1078 /**
1079 * Returns true if represented class is serializable (but not
1080 * externalizable) and defines a conformant readObject method. Otherwise,
1081 * returns false.
1082 */
1083 boolean hasReadObjectMethod() {
1084 requireInitialized();
1085 return (readObjectMethod != null);
1086 }
1087
1088 /**
1089 * Returns true if represented class is serializable (but not
1090 * externalizable) and defines a conformant readObjectNoData method.
1091 * Otherwise, returns false.
1092 */
1093 boolean hasReadObjectNoDataMethod() {
1094 requireInitialized();
1095 return (readObjectNoDataMethod != null);
1096 }
1097
1098 /**
1099 * Returns true if represented class is serializable or externalizable and
1100 * defines a conformant writeReplace method. Otherwise, returns false.
1101 */
1102 boolean hasWriteReplaceMethod() {
1103 requireInitialized();
1104 return (writeReplaceMethod != null);
1105 }
1106
1107 /**
1108 * Returns true if represented class is serializable or externalizable and
1109 * defines a conformant readResolve method. Otherwise, returns false.
1110 */
1111 boolean hasReadResolveMethod() {
1112 requireInitialized();
1113 return (readResolveMethod != null);
1114 }
1115
1116 /**
1117 * Creates a new instance of the represented class. If the class is
1118 * externalizable, invokes its public no-arg constructor; otherwise, if the
1119 * class is serializable, invokes the no-arg constructor of the first
1120 * non-serializable superclass. Throws UnsupportedOperationException if
1121 * this class descriptor is not associated with a class, if the associated
1122 * class is non-serializable or if the appropriate no-arg constructor is
1123 * inaccessible/unavailable.
1124 */
1125 Object newInstance()
1126 throws InstantiationException, InvocationTargetException,
1127 UnsupportedOperationException
1128 {
1129 requireInitialized();
1130 if (cons != null) {
1131 try {
1132 if (domains == null || domains.length == 0) {
1133 return cons.newInstance();
1134 } else {
1135 JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess();
1136 PrivilegedAction<?> pea = () -> {
1137 try {
1138 return cons.newInstance();
1139 } catch (InstantiationException
1140 | InvocationTargetException
1141 | IllegalAccessException x) {
1142 throw new UndeclaredThrowableException(x);
1143 }
1144 }; // Can't use PrivilegedExceptionAction with jsa
1145 try {
1146 return jsa.doIntersectionPrivilege(pea,
1147 AccessController.getContext(),
1148 new AccessControlContext(domains));
1149 } catch (UndeclaredThrowableException x) {
1150 Throwable cause = x.getCause();
1151 if (cause instanceof InstantiationException)
1152 throw (InstantiationException) cause;
1153 if (cause instanceof InvocationTargetException)
1154 throw (InvocationTargetException) cause;
1155 if (cause instanceof IllegalAccessException)
1156 throw (IllegalAccessException) cause;
1157 // not supposed to happen
1158 throw x;
1159 }
1160 }
1161 } catch (IllegalAccessException ex) {
1162 // should not occur, as access checks have been suppressed
1163 throw new InternalError(ex);
1164 } catch (InstantiationError err) {
1165 var ex = new InstantiationException();
1166 ex.initCause(err);
1167 throw ex;
1168 }
1169 } else {
1170 throw new UnsupportedOperationException();
1171 }
1172 }
1173
1174 /**
1175 * Invokes the writeObject method of the represented serializable class.
1176 * Throws UnsupportedOperationException if this class descriptor is not
1177 * associated with a class, or if the class is externalizable,
1178 * non-serializable or does not define writeObject.
1179 */
1180 void invokeWriteObject(Object obj, ObjectOutputStream out)
1181 throws IOException, UnsupportedOperationException
1182 {
1183 requireInitialized();
1184 if (writeObjectMethod != null) {
1185 try {
1186 writeObjectMethod.invoke(obj, new Object[]{ out });
1187 } catch (InvocationTargetException ex) {
1188 Throwable th = ex.getTargetException();
1189 if (th instanceof IOException) {
1190 throw (IOException) th;
1191 } else {
1192 throwMiscException(th);
1193 }
1194 } catch (IllegalAccessException ex) {
1195 // should not occur, as access checks have been suppressed
1196 throw new InternalError(ex);
1197 }
1198 } else {
1199 throw new UnsupportedOperationException();
1200 }
1201 }
1202
1203 /**
1204 * Invokes the readObject method of the represented serializable class.
1205 * Throws UnsupportedOperationException if this class descriptor is not
1206 * associated with a class, or if the class is externalizable,
1207 * non-serializable or does not define readObject.
1208 */
1209 void invokeReadObject(Object obj, ObjectInputStream in)
1210 throws ClassNotFoundException, IOException,
1211 UnsupportedOperationException
1212 {
1213 requireInitialized();
1214 if (readObjectMethod != null) {
1215 try {
1216 readObjectMethod.invoke(obj, new Object[]{ in });
1217 } catch (InvocationTargetException ex) {
1218 Throwable th = ex.getTargetException();
1219 if (th instanceof ClassNotFoundException) {
1220 throw (ClassNotFoundException) th;
1221 } else if (th instanceof IOException) {
1222 throw (IOException) th;
1223 } else {
1224 throwMiscException(th);
1225 }
1226 } catch (IllegalAccessException ex) {
1227 // should not occur, as access checks have been suppressed
1228 throw new InternalError(ex);
1229 }
1230 } else {
1231 throw new UnsupportedOperationException();
1232 }
1233 }
1234
1235 /**
1236 * Invokes the readObjectNoData method of the represented serializable
1237 * class. Throws UnsupportedOperationException if this class descriptor is
1238 * not associated with a class, or if the class is externalizable,
1239 * non-serializable or does not define readObjectNoData.
1240 */
1241 void invokeReadObjectNoData(Object obj)
1242 throws IOException, UnsupportedOperationException
1243 {
1244 requireInitialized();
1245 if (readObjectNoDataMethod != null) {
1246 try {
1247 readObjectNoDataMethod.invoke(obj, (Object[]) null);
1248 } catch (InvocationTargetException ex) {
1249 Throwable th = ex.getTargetException();
1250 if (th instanceof ObjectStreamException) {
1251 throw (ObjectStreamException) th;
1252 } else {
1253 throwMiscException(th);
1254 }
1255 } catch (IllegalAccessException ex) {
1256 // should not occur, as access checks have been suppressed
1257 throw new InternalError(ex);
1258 }
1259 } else {
1260 throw new UnsupportedOperationException();
1261 }
1262 }
1263
1264 /**
1265 * Invokes the writeReplace method of the represented serializable class and
1266 * returns the result. Throws UnsupportedOperationException if this class
1267 * descriptor is not associated with a class, or if the class is
1268 * non-serializable or does not define writeReplace.
1269 */
1270 Object invokeWriteReplace(Object obj)
1271 throws IOException, UnsupportedOperationException
1272 {
1273 requireInitialized();
1274 if (writeReplaceMethod != null) {
1275 try {
1276 return writeReplaceMethod.invoke(obj, (Object[]) null);
1277 } catch (InvocationTargetException ex) {
1278 Throwable th = ex.getTargetException();
1279 if (th instanceof ObjectStreamException) {
1280 throw (ObjectStreamException) th;
1281 } else {
1282 throwMiscException(th);
1283 throw new InternalError(th); // never reached
1284 }
1285 } catch (IllegalAccessException ex) {
1286 // should not occur, as access checks have been suppressed
1287 throw new InternalError(ex);
1288 }
1289 } else {
1290 throw new UnsupportedOperationException();
1291 }
1292 }
1293
1294 /**
1295 * Invokes the readResolve method of the represented serializable class and
1296 * returns the result. Throws UnsupportedOperationException if this class
1297 * descriptor is not associated with a class, or if the class is
1298 * non-serializable or does not define readResolve.
1299 */
1300 Object invokeReadResolve(Object obj)
1301 throws IOException, UnsupportedOperationException
1302 {
1303 requireInitialized();
1304 if (readResolveMethod != null) {
1305 try {
1306 return readResolveMethod.invoke(obj, (Object[]) null);
1307 } catch (InvocationTargetException ex) {
1308 Throwable th = ex.getTargetException();
1309 if (th instanceof ObjectStreamException) {
1310 throw (ObjectStreamException) th;
1311 } else {
1312 throwMiscException(th);
1313 throw new InternalError(th); // never reached
1314 }
1315 } catch (IllegalAccessException ex) {
1316 // should not occur, as access checks have been suppressed
1317 throw new InternalError(ex);
1318 }
1319 } else {
1320 throw new UnsupportedOperationException();
1321 }
1322 }
1323
1324 /**
1325 * Class representing the portion of an object's serialized form allotted
1326 * to data described by a given class descriptor. If "hasData" is false,
1327 * the object's serialized form does not contain data associated with the
1328 * class descriptor.
1329 */
1330 static class ClassDataSlot {
1331
1332 /** class descriptor "occupying" this slot */
1333 final ObjectStreamClass desc;
1334 /** true if serialized form includes data for this slot's descriptor */
1335 final boolean hasData;
1336
1337 ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
1338 this.desc = desc;
1339 this.hasData = hasData;
1340 }
1341 }
1342
1343 /**
1344 * Returns array of ClassDataSlot instances representing the data layout
1345 * (including superclass data) for serialized objects described by this
1346 * class descriptor. ClassDataSlots are ordered by inheritance with those
1347 * containing "higher" superclasses appearing first. The final
1348 * ClassDataSlot contains a reference to this descriptor.
1349 */
1350 ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
1351 // REMIND: synchronize instead of relying on volatile?
1352 if (dataLayout == null) {
1353 dataLayout = getClassDataLayout0();
1354 }
1355 return dataLayout;
1356 }
1357
1358 private ClassDataSlot[] getClassDataLayout0()
1359 throws InvalidClassException
1360 {
1361 ArrayList<ClassDataSlot> slots = new ArrayList<>();
1362 Class<?> start = cl, end = cl;
1363
1364 // locate closest non-serializable superclass
1365 while (end != null && Serializable.class.isAssignableFrom(end)) {
1366 end = end.getSuperclass();
1367 }
1368
1369 HashSet<String> oscNames = new HashSet<>(3);
1370
1371 for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
1372 if (oscNames.contains(d.name)) {
1373 throw new InvalidClassException("Circular reference.");
1374 } else {
1375 oscNames.add(d.name);
1376 }
1377
1378 // search up inheritance hierarchy for class with matching name
1379 String searchName = (d.cl != null) ? d.cl.getName() : d.name;
1380 Class<?> match = null;
1381 for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1382 if (searchName.equals(c.getName())) {
1383 match = c;
1384 break;
1385 }
1386 }
1387
1388 // add "no data" slot for each unmatched class below match
1389 if (match != null) {
1390 for (Class<?> c = start; c != match; c = c.getSuperclass()) {
1391 slots.add(new ClassDataSlot(
1392 ObjectStreamClass.lookup(c, true), false));
1393 }
1394 start = match.getSuperclass();
1395 }
1396
1397 // record descriptor/class pairing
1398 slots.add(new ClassDataSlot(d.getVariantFor(match), true));
1399 }
1400
1401 // add "no data" slot for any leftover unmatched classes
1402 for (Class<?> c = start; c != end; c = c.getSuperclass()) {
1403 slots.add(new ClassDataSlot(
1404 ObjectStreamClass.lookup(c, true), false));
1405 }
1406
1407 // order slots from superclass -> subclass
1408 Collections.reverse(slots);
1409 return slots.toArray(new ClassDataSlot[slots.size()]);
1410 }
1411
1412 /**
1413 * Returns aggregate size (in bytes) of marshalled primitive field values
1414 * for represented class.
1415 */
1416 int getPrimDataSize() {
1417 return primDataSize;
1418 }
1419
1420 /**
1421 * Returns number of non-primitive serializable fields of represented
1422 * class.
1423 */
1424 int getNumObjFields() {
1425 return numObjFields;
1426 }
1427
1428 /**
1429 * Fetches the serializable primitive field values of object obj and
1430 * marshals them into byte array buf starting at offset 0. It is the
1431 * responsibility of the caller to ensure that obj is of the proper type if
1432 * non-null.
1433 */
1434 void getPrimFieldValues(Object obj, byte[] buf) {
1435 fieldRefl.getPrimFieldValues(obj, buf);
1436 }
1437
1438 /**
1439 * Sets the serializable primitive fields of object obj using values
1440 * unmarshalled from byte array buf starting at offset 0. It is the
1441 * responsibility of the caller to ensure that obj is of the proper type if
1442 * non-null.
1443 */
1444 void setPrimFieldValues(Object obj, byte[] buf) {
1445 fieldRefl.setPrimFieldValues(obj, buf);
1446 }
1447
1448 /**
1449 * Fetches the serializable object field values of object obj and stores
1450 * them in array vals starting at offset 0. It is the responsibility of
1451 * the caller to ensure that obj is of the proper type if non-null.
1452 */
1453 void getObjFieldValues(Object obj, Object[] vals) {
1454 fieldRefl.getObjFieldValues(obj, vals);
1455 }
1456
1457 /**
1458 * Checks that the given values, from array vals starting at offset 0,
1459 * are assignable to the given serializable object fields.
1460 * @throws ClassCastException if any value is not assignable
1461 */
1462 void checkObjFieldValueTypes(Object obj, Object[] vals) {
1463 fieldRefl.checkObjectFieldValueTypes(obj, vals);
1464 }
1465
1466 /**
1467 * Sets the serializable object fields of object obj using values from
1468 * array vals starting at offset 0. It is the responsibility of the caller
1469 * to ensure that obj is of the proper type if non-null.
1470 */
1471 void setObjFieldValues(Object obj, Object[] vals) {
1472 fieldRefl.setObjFieldValues(obj, vals);
1473 }
1474
1475 /**
1476 * Calculates and sets serializable field offsets, as well as primitive
1477 * data size and object field count totals. Throws InvalidClassException
1478 * if fields are illegally ordered.
1479 */
1480 private void computeFieldOffsets() throws InvalidClassException {
1481 primDataSize = 0;
1482 numObjFields = 0;
1483 int firstObjIndex = -1;
1484
1485 for (int i = 0; i < fields.length; i++) {
1486 ObjectStreamField f = fields[i];
1487 switch (f.getTypeCode()) {
1488 case 'Z':
1489 case 'B':
1490 f.setOffset(primDataSize++);
1491 break;
1492
1493 case 'C':
1494 case 'S':
1495 f.setOffset(primDataSize);
1496 primDataSize += 2;
1497 break;
1498
1499 case 'I':
1500 case 'F':
1501 f.setOffset(primDataSize);
1502 primDataSize += 4;
1503 break;
1504
1505 case 'J':
1506 case 'D':
1507 f.setOffset(primDataSize);
1508 primDataSize += 8;
1509 break;
1510
1511 case '[':
1512 case 'L':
1513 f.setOffset(numObjFields++);
1514 if (firstObjIndex == -1) {
1515 firstObjIndex = i;
1516 }
1517 break;
1518
1519 default:
1520 throw new InternalError();
1521 }
1522 }
1523 if (firstObjIndex != -1 &&
1524 firstObjIndex + numObjFields != fields.length)
1525 {
1526 throw new InvalidClassException(name, "illegal field order");
1527 }
1528 }
1529
1530 /**
1531 * If given class is the same as the class associated with this class
1532 * descriptor, returns reference to this class descriptor. Otherwise,
1533 * returns variant of this class descriptor bound to given class.
1534 */
1535 private ObjectStreamClass getVariantFor(Class<?> cl)
1536 throws InvalidClassException
1537 {
1538 if (this.cl == cl) {
1539 return this;
1540 }
1541 ObjectStreamClass desc = new ObjectStreamClass();
1542 if (isProxy) {
1543 desc.initProxy(cl, null, superDesc);
1544 } else {
1545 desc.initNonProxy(this, cl, null, superDesc);
1546 }
1547 return desc;
1548 }
1549
1550 /**
1551 * Returns public no-arg constructor of given class, or null if none found.
1552 * Access checks are disabled on the returned constructor (if any), since
1553 * the defining class may still be non-public.
1554 */
1555 private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
1556 try {
1557 Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
1558 cons.setAccessible(true);
1559 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
1560 cons : null;
1561 } catch (NoSuchMethodException ex) {
1562 return null;
1563 }
1564 }
1565
1566 /**
1567 * Returns subclass-accessible no-arg constructor of first non-serializable
1568 * superclass, or null if none found. Access checks are disabled on the
1569 * returned constructor (if any).
1570 */
1571 private static Constructor<?> getSerializableConstructor(Class<?> cl) {
1572 return reflFactory.newConstructorForSerialization(cl);
1573 }
1574
1575 /**
1576 * Returns the canonical constructor for the given record class, or null if
1577 * the not found ( which should never happen for correctly generated record
1578 * classes ).
1579 */
1580 @SuppressWarnings("preview")
1581 private static MethodHandle canonicalRecordCtr(Class<?> cls) {
1582 assert isRecord(cls) : "Expected record, got: " + cls;
1583 PrivilegedAction<MethodHandle> pa = () -> {
1584 Class<?>[] paramTypes = Arrays.stream(cls.getRecordComponents())
1585 .map(RecordComponent::getType)
1586 .toArray(Class<?>[]::new);
1587 try {
1588 Constructor<?> ctr = cls.getConstructor(paramTypes);
1589 ctr.setAccessible(true);
1590 return MethodHandles.lookup().unreflectConstructor(ctr);
1591 } catch (IllegalAccessException | NoSuchMethodException e) {
1592 return null;
1593 }
1594 };
1595 return AccessController.doPrivileged(pa);
1596 }
1597
1598 /**
1599 * Returns the canonical constructor, if the local class equivalent of this
1600 * stream class descriptor is a record class, otherwise null.
1601 */
1602 MethodHandle getRecordConstructor() {
1603 return canonicalCtr;
1604 }
1605
1606 /**
1607 * Returns non-static, non-abstract method with given signature provided it
1608 * is defined by or accessible (via inheritance) by the given class, or
1609 * null if no match found. Access checks are disabled on the returned
1610 * method (if any).
1611 */
1612 private static Method getInheritableMethod(Class<?> cl, String name,
1613 Class<?>[] argTypes,
1614 Class<?> returnType)
1615 {
1616 Method meth = null;
1617 Class<?> defCl = cl;
1618 while (defCl != null) {
1619 try {
1620 meth = defCl.getDeclaredMethod(name, argTypes);
1621 break;
1622 } catch (NoSuchMethodException ex) {
1623 defCl = defCl.getSuperclass();
1624 }
1625 }
1626
1627 if ((meth == null) || (meth.getReturnType() != returnType)) {
1628 return null;
1629 }
1630 meth.setAccessible(true);
1631 int mods = meth.getModifiers();
1632 if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
1633 return null;
1634 } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
1635 return meth;
1636 } else if ((mods & Modifier.PRIVATE) != 0) {
1637 return (cl == defCl) ? meth : null;
1638 } else {
1639 return packageEquals(cl, defCl) ? meth : null;
1640 }
1641 }
1642
1643 /**
1644 * Returns non-static private method with given signature defined by given
1645 * class, or null if none found. Access checks are disabled on the
1646 * returned method (if any).
1647 */
1648 private static Method getPrivateMethod(Class<?> cl, String name,
1649 Class<?>[] argTypes,
1650 Class<?> returnType)
1651 {
1652 try {
1653 Method meth = cl.getDeclaredMethod(name, argTypes);
1654 meth.setAccessible(true);
1655 int mods = meth.getModifiers();
1656 return ((meth.getReturnType() == returnType) &&
1657 ((mods & Modifier.STATIC) == 0) &&
1658 ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
1659 } catch (NoSuchMethodException ex) {
1660 return null;
1661 }
1662 }
1663
1664 /**
1665 * Returns true if classes are defined in the same runtime package, false
1666 * otherwise.
1667 */
1668 private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
1669 return (cl1.getClassLoader() == cl2.getClassLoader() &&
1670 cl1.getPackageName().equals(cl2.getPackageName()));
1671 }
1672
1673 /**
1674 * Compares class names for equality, ignoring package names. Returns true
1675 * if class names equal, false otherwise.
1676 */
1677 private static boolean classNamesEqual(String name1, String name2) {
1678 int idx1 = name1.lastIndexOf('.') + 1;
1679 int idx2 = name2.lastIndexOf('.') + 1;
1680 int len1 = name1.length() - idx1;
1681 int len2 = name2.length() - idx2;
1682 return len1 == len2 &&
1683 name1.regionMatches(idx1, name2, idx2, len1);
1684 }
1685
1686 /**
1687 * Returns JVM type signature for given list of parameters and return type.
1688 */
1689 private static String getMethodSignature(Class<?>[] paramTypes,
1690 Class<?> retType)
1691 {
1692 StringBuilder sb = new StringBuilder();
1693 sb.append('(');
1694 for (int i = 0; i < paramTypes.length; i++) {
1695 appendClassSignature(sb, paramTypes[i]);
1696 }
1697 sb.append(')');
1698 appendClassSignature(sb, retType);
1699 return sb.toString();
1700 }
1701
1702 /**
1703 * Convenience method for throwing an exception that is either a
1704 * RuntimeException, Error, or of some unexpected type (in which case it is
1705 * wrapped inside an IOException).
1706 */
1707 private static void throwMiscException(Throwable th) throws IOException {
1708 if (th instanceof RuntimeException) {
1709 throw (RuntimeException) th;
1710 } else if (th instanceof Error) {
1711 throw (Error) th;
1712 } else {
1713 IOException ex = new IOException("unexpected exception type");
1714 ex.initCause(th);
1715 throw ex;
1716 }
1717 }
1718
1719 /**
1720 * Returns ObjectStreamField array describing the serializable fields of
1721 * the given class. Serializable fields backed by an actual field of the
1722 * class are represented by ObjectStreamFields with corresponding non-null
1723 * Field objects. Throws InvalidClassException if the (explicitly
1724 * declared) serializable fields are invalid.
1725 */
1726 private static ObjectStreamField[] getSerialFields(Class<?> cl)
1727 throws InvalidClassException
1728 {
1729 if (!Serializable.class.isAssignableFrom(cl))
1730 return NO_FIELDS;
1731
1732 ObjectStreamField[] fields;
1733 if (isRecord(cl)) {
1734 fields = getDefaultSerialFields(cl);
1735 Arrays.sort(fields);
1736 } else if (!Externalizable.class.isAssignableFrom(cl) &&
1737 !Proxy.isProxyClass(cl) &&
1738 !cl.isInterface()) {
1739 if ((fields = getDeclaredSerialFields(cl)) == null) {
1740 fields = getDefaultSerialFields(cl);
1741 }
1742 Arrays.sort(fields);
1743 } else {
1744 fields = NO_FIELDS;
1745 }
1746 return fields;
1747 }
1748
1749 /**
1750 * Returns serializable fields of given class as defined explicitly by a
1751 * "serialPersistentFields" field, or null if no appropriate
1752 * "serialPersistentFields" field is defined. Serializable fields backed
1753 * by an actual field of the class are represented by ObjectStreamFields
1754 * with corresponding non-null Field objects. For compatibility with past
1755 * releases, a "serialPersistentFields" field with a null value is
1756 * considered equivalent to not declaring "serialPersistentFields". Throws
1757 * InvalidClassException if the declared serializable fields are
1758 * invalid--e.g., if multiple fields share the same name.
1759 */
1760 private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
1761 throws InvalidClassException
1762 {
1763 ObjectStreamField[] serialPersistentFields = null;
1764 try {
1765 Field f = cl.getDeclaredField("serialPersistentFields");
1766 int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
1767 if ((f.getModifiers() & mask) == mask) {
1768 f.setAccessible(true);
1769 serialPersistentFields = (ObjectStreamField[]) f.get(null);
1770 }
1771 } catch (Exception ex) {
1772 }
1773 if (serialPersistentFields == null) {
1774 return null;
1775 } else if (serialPersistentFields.length == 0) {
1776 return NO_FIELDS;
1777 }
1778
1779 ObjectStreamField[] boundFields =
1780 new ObjectStreamField[serialPersistentFields.length];
1781 Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
1782
1783 for (int i = 0; i < serialPersistentFields.length; i++) {
1784 ObjectStreamField spf = serialPersistentFields[i];
1785
1786 String fname = spf.getName();
1787 if (fieldNames.contains(fname)) {
1788 throw new InvalidClassException(
1789 "multiple serializable fields named " + fname);
1790 }
1791 fieldNames.add(fname);
1792
1793 try {
1794 Field f = cl.getDeclaredField(fname);
1795 if ((f.getType() == spf.getType()) &&
1796 ((f.getModifiers() & Modifier.STATIC) == 0))
1797 {
1798 boundFields[i] =
1799 new ObjectStreamField(f, spf.isUnshared(), true);
1800 }
1801 } catch (NoSuchFieldException ex) {
1802 }
1803 if (boundFields[i] == null) {
1804 boundFields[i] = new ObjectStreamField(
1805 fname, spf.getType(), spf.isUnshared());
1806 }
1807 }
1808 return boundFields;
1809 }
1810
1811 /**
1812 * Returns array of ObjectStreamFields corresponding to all non-static
1813 * non-transient fields declared by given class. Each ObjectStreamField
1814 * contains a Field object for the field it represents. If no default
1815 * serializable fields exist, NO_FIELDS is returned.
1816 */
1817 private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
1818 Field[] clFields = cl.getDeclaredFields();
1819 ArrayList<ObjectStreamField> list = new ArrayList<>();
1820 int mask = Modifier.STATIC | Modifier.TRANSIENT;
1821
1822 for (int i = 0; i < clFields.length; i++) {
1823 if ((clFields[i].getModifiers() & mask) == 0) {
1824 list.add(new ObjectStreamField(clFields[i], false, true));
1825 }
1826 }
1827 int size = list.size();
1828 return (size == 0) ? NO_FIELDS :
1829 list.toArray(new ObjectStreamField[size]);
1830 }
1831
1832 /**
1833 * Returns explicit serial version UID value declared by given class, or
1834 * null if none.
1835 */
1836 private static Long getDeclaredSUID(Class<?> cl) {
1837 try {
1838 Field f = cl.getDeclaredField("serialVersionUID");
1839 int mask = Modifier.STATIC | Modifier.FINAL;
1840 if ((f.getModifiers() & mask) == mask) {
1841 f.setAccessible(true);
1842 return Long.valueOf(f.getLong(null));
1843 }
1844 } catch (Exception ex) {
1845 }
1846 return null;
1847 }
1848
1849 /**
1850 * Computes the default serial version UID value for the given class.
1851 */
1852 private static long computeDefaultSUID(Class<?> cl) {
1853 if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
1854 {
1855 return 0L;
1856 }
1857
1858 try {
1859 ByteArrayOutputStream bout = new ByteArrayOutputStream();
1860 DataOutputStream dout = new DataOutputStream(bout);
1861
1862 dout.writeUTF(cl.getName());
1863
1864 int classMods = cl.getModifiers() &
1865 (Modifier.PUBLIC | Modifier.FINAL |
1866 Modifier.INTERFACE | Modifier.ABSTRACT);
1867
1868 /*
1869 * compensate for javac bug in which ABSTRACT bit was set for an
1870 * interface only if the interface declared methods
1871 */
1872 Method[] methods = cl.getDeclaredMethods();
1873 if ((classMods & Modifier.INTERFACE) != 0) {
1874 classMods = (methods.length > 0) ?
1875 (classMods | Modifier.ABSTRACT) :
1876 (classMods & ~Modifier.ABSTRACT);
1877 }
1878 dout.writeInt(classMods);
1879
1880 if (!cl.isArray()) {
1881 /*
1882 * compensate for change in 1.2FCS in which
1883 * Class.getInterfaces() was modified to return Cloneable and
1884 * Serializable for array classes.
1885 */
1886 Class<?>[] interfaces = cl.getInterfaces();
1887 String[] ifaceNames = new String[interfaces.length];
1888 for (int i = 0; i < interfaces.length; i++) {
1889 ifaceNames[i] = interfaces[i].getName();
1890 }
1891 Arrays.sort(ifaceNames);
1892 for (int i = 0; i < ifaceNames.length; i++) {
1893 dout.writeUTF(ifaceNames[i]);
1894 }
1895 }
1896
1897 Field[] fields = cl.getDeclaredFields();
1898 MemberSignature[] fieldSigs = new MemberSignature[fields.length];
1899 for (int i = 0; i < fields.length; i++) {
1900 fieldSigs[i] = new MemberSignature(fields[i]);
1901 }
1902 Arrays.sort(fieldSigs, new Comparator<>() {
1903 public int compare(MemberSignature ms1, MemberSignature ms2) {
1904 return ms1.name.compareTo(ms2.name);
1905 }
1906 });
1907 for (int i = 0; i < fieldSigs.length; i++) {
1908 MemberSignature sig = fieldSigs[i];
1909 int mods = sig.member.getModifiers() &
1910 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1911 Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
1912 Modifier.TRANSIENT);
1913 if (((mods & Modifier.PRIVATE) == 0) ||
1914 ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
1915 {
1916 dout.writeUTF(sig.name);
1917 dout.writeInt(mods);
1918 dout.writeUTF(sig.signature);
1919 }
1920 }
1921
1922 if (hasStaticInitializer(cl)) {
1923 dout.writeUTF("<clinit>");
1924 dout.writeInt(Modifier.STATIC);
1925 dout.writeUTF("()V");
1926 }
1927
1928 Constructor<?>[] cons = cl.getDeclaredConstructors();
1929 MemberSignature[] consSigs = new MemberSignature[cons.length];
1930 for (int i = 0; i < cons.length; i++) {
1931 consSigs[i] = new MemberSignature(cons[i]);
1932 }
1933 Arrays.sort(consSigs, new Comparator<>() {
1934 public int compare(MemberSignature ms1, MemberSignature ms2) {
1935 return ms1.signature.compareTo(ms2.signature);
1936 }
1937 });
1938 for (int i = 0; i < consSigs.length; i++) {
1939 MemberSignature sig = consSigs[i];
1940 int mods = sig.member.getModifiers() &
1941 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1942 Modifier.STATIC | Modifier.FINAL |
1943 Modifier.SYNCHRONIZED | Modifier.NATIVE |
1944 Modifier.ABSTRACT | Modifier.STRICT);
1945 if ((mods & Modifier.PRIVATE) == 0) {
1946 dout.writeUTF("<init>");
1947 dout.writeInt(mods);
1948 dout.writeUTF(sig.signature.replace('/', '.'));
1949 }
1950 }
1951
1952 MemberSignature[] methSigs = new MemberSignature[methods.length];
1953 for (int i = 0; i < methods.length; i++) {
1954 methSigs[i] = new MemberSignature(methods[i]);
1955 }
1956 Arrays.sort(methSigs, new Comparator<>() {
1957 public int compare(MemberSignature ms1, MemberSignature ms2) {
1958 int comp = ms1.name.compareTo(ms2.name);
1959 if (comp == 0) {
1960 comp = ms1.signature.compareTo(ms2.signature);
1961 }
1962 return comp;
1963 }
1964 });
1965 for (int i = 0; i < methSigs.length; i++) {
1966 MemberSignature sig = methSigs[i];
1967 int mods = sig.member.getModifiers() &
1968 (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
1969 Modifier.STATIC | Modifier.FINAL |
1970 Modifier.SYNCHRONIZED | Modifier.NATIVE |
1971 Modifier.ABSTRACT | Modifier.STRICT);
1972 if ((mods & Modifier.PRIVATE) == 0) {
1973 dout.writeUTF(sig.name);
1974 dout.writeInt(mods);
1975 dout.writeUTF(sig.signature.replace('/', '.'));
1976 }
1977 }
1978
1979 dout.flush();
1980
1981 MessageDigest md = MessageDigest.getInstance("SHA");
1982 byte[] hashBytes = md.digest(bout.toByteArray());
1983 long hash = 0;
1984 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
1985 hash = (hash << 8) | (hashBytes[i] & 0xFF);
1986 }
1987 return hash;
1988 } catch (IOException ex) {
1989 throw new InternalError(ex);
1990 } catch (NoSuchAlgorithmException ex) {
1991 throw new SecurityException(ex.getMessage());
1992 }
1993 }
1994
1995 /**
1996 * Returns true if the given class defines a static initializer method,
1997 * false otherwise.
1998 */
1999 private static native boolean hasStaticInitializer(Class<?> cl);
2000
2001 /**
2002 * Class for computing and caching field/constructor/method signatures
2003 * during serialVersionUID calculation.
2004 */
2005 private static class MemberSignature {
2006
2007 public final Member member;
2008 public final String name;
2009 public final String signature;
2010
2011 public MemberSignature(Field field) {
2012 member = field;
2013 name = field.getName();
2014 signature = getClassSignature(field.getType());
2015 }
2016
2017 public MemberSignature(Constructor<?> cons) {
2018 member = cons;
2019 name = cons.getName();
2020 signature = getMethodSignature(
2021 cons.getParameterTypes(), Void.TYPE);
2022 }
2023
2024 public MemberSignature(Method meth) {
2025 member = meth;
2026 name = meth.getName();
2027 signature = getMethodSignature(
2028 meth.getParameterTypes(), meth.getReturnType());
2029 }
2030 }
2031
2032 /**
2033 * Class for setting and retrieving serializable field values in batch.
2034 */
2035 // REMIND: dynamically generate these?
2036 private static class FieldReflector {
2037
2038 /** handle for performing unsafe operations */
2039 private static final Unsafe unsafe = Unsafe.getUnsafe();
2040
2041 /** fields to operate on */
2042 private final ObjectStreamField[] fields;
2043 /** number of primitive fields */
2044 private final int numPrimFields;
2045 /** unsafe field keys for reading fields - may contain dupes */
2046 private final long[] readKeys;
2047 /** unsafe fields keys for writing fields - no dupes */
2048 private final long[] writeKeys;
2049 /** field data offsets */
2050 private final int[] offsets;
2051 /** field type codes */
2052 private final char[] typeCodes;
2053 /** field types */
2054 private final Class<?>[] types;
2055
2056 /**
2057 * Constructs FieldReflector capable of setting/getting values from the
2058 * subset of fields whose ObjectStreamFields contain non-null
2059 * reflective Field objects. ObjectStreamFields with null Fields are
2060 * treated as filler, for which get operations return default values
2061 * and set operations discard given values.
2062 */
2063 FieldReflector(ObjectStreamField[] fields) {
2064 this.fields = fields;
2065 int nfields = fields.length;
2066 readKeys = new long[nfields];
2067 writeKeys = new long[nfields];
2068 offsets = new int[nfields];
2069 typeCodes = new char[nfields];
2070 ArrayList<Class<?>> typeList = new ArrayList<>();
2071 Set<Long> usedKeys = new HashSet<>();
2072
2073
2074 for (int i = 0; i < nfields; i++) {
2075 ObjectStreamField f = fields[i];
2076 Field rf = f.getField();
2077 long key = (rf != null) ?
2078 unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
2079 readKeys[i] = key;
2080 writeKeys[i] = usedKeys.add(key) ?
2081 key : Unsafe.INVALID_FIELD_OFFSET;
2082 offsets[i] = f.getOffset();
2083 typeCodes[i] = f.getTypeCode();
2084 if (!f.isPrimitive()) {
2085 typeList.add((rf != null) ? rf.getType() : null);
2086 }
2087 }
2088
2089 types = typeList.toArray(new Class<?>[typeList.size()]);
2090 numPrimFields = nfields - types.length;
2091 }
2092
2093 /**
2094 * Returns list of ObjectStreamFields representing fields operated on
2095 * by this reflector. The shared/unshared values and Field objects
2096 * contained by ObjectStreamFields in the list reflect their bindings
2097 * to locally defined serializable fields.
2098 */
2099 ObjectStreamField[] getFields() {
2100 return fields;
2101 }
2102
2103 /**
2104 * Fetches the serializable primitive field values of object obj and
2105 * marshals them into byte array buf starting at offset 0. The caller
2106 * is responsible for ensuring that obj is of the proper type.
2107 */
2108 void getPrimFieldValues(Object obj, byte[] buf) {
2109 if (obj == null) {
2110 throw new NullPointerException();
2111 }
2112 /* assuming checkDefaultSerialize() has been called on the class
2113 * descriptor this FieldReflector was obtained from, no field keys
2114 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2115 */
2116 for (int i = 0; i < numPrimFields; i++) {
2117 long key = readKeys[i];
2118 int off = offsets[i];
2119 switch (typeCodes[i]) {
2120 case 'Z':
2121 Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key));
2122 break;
2123
2124 case 'B':
2125 buf[off] = unsafe.getByte(obj, key);
2126 break;
2127
2128 case 'C':
2129 Bits.putChar(buf, off, unsafe.getChar(obj, key));
2130 break;
2131
2132 case 'S':
2133 Bits.putShort(buf, off, unsafe.getShort(obj, key));
2134 break;
2135
2136 case 'I':
2137 Bits.putInt(buf, off, unsafe.getInt(obj, key));
2138 break;
2139
2140 case 'F':
2141 Bits.putFloat(buf, off, unsafe.getFloat(obj, key));
2142 break;
2143
2144 case 'J':
2145 Bits.putLong(buf, off, unsafe.getLong(obj, key));
2146 break;
2147
2148 case 'D':
2149 Bits.putDouble(buf, off, unsafe.getDouble(obj, key));
2150 break;
2151
2152 default:
2153 throw new InternalError();
2154 }
2155 }
2156 }
2157
2158 /**
2159 * Sets the serializable primitive fields of object obj using values
2160 * unmarshalled from byte array buf starting at offset 0. The caller
2161 * is responsible for ensuring that obj is of the proper type.
2162 */
2163 void setPrimFieldValues(Object obj, byte[] buf) {
2164 if (obj == null) {
2165 throw new NullPointerException();
2166 }
2167 for (int i = 0; i < numPrimFields; i++) {
2168 long key = writeKeys[i];
2169 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2170 continue; // discard value
2171 }
2172 int off = offsets[i];
2173 switch (typeCodes[i]) {
2174 case 'Z':
2175 unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off));
2176 break;
2177
2178 case 'B':
2179 unsafe.putByte(obj, key, buf[off]);
2180 break;
2181
2182 case 'C':
2183 unsafe.putChar(obj, key, Bits.getChar(buf, off));
2184 break;
2185
2186 case 'S':
2187 unsafe.putShort(obj, key, Bits.getShort(buf, off));
2188 break;
2189
2190 case 'I':
2191 unsafe.putInt(obj, key, Bits.getInt(buf, off));
2192 break;
2193
2194 case 'F':
2195 unsafe.putFloat(obj, key, Bits.getFloat(buf, off));
2196 break;
2197
2198 case 'J':
2199 unsafe.putLong(obj, key, Bits.getLong(buf, off));
2200 break;
2201
2202 case 'D':
2203 unsafe.putDouble(obj, key, Bits.getDouble(buf, off));
2204 break;
2205
2206 default:
2207 throw new InternalError();
2208 }
2209 }
2210 }
2211
2212 /**
2213 * Fetches the serializable object field values of object obj and
2214 * stores them in array vals starting at offset 0. The caller is
2215 * responsible for ensuring that obj is of the proper type.
2216 */
2217 void getObjFieldValues(Object obj, Object[] vals) {
2218 if (obj == null) {
2219 throw new NullPointerException();
2220 }
2221 /* assuming checkDefaultSerialize() has been called on the class
2222 * descriptor this FieldReflector was obtained from, no field keys
2223 * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
2224 */
2225 for (int i = numPrimFields; i < fields.length; i++) {
2226 switch (typeCodes[i]) {
2227 case 'L':
2228 case '[':
2229 vals[offsets[i]] = unsafe.getReference(obj, readKeys[i]);
2230 break;
2231
2232 default:
2233 throw new InternalError();
2234 }
2235 }
2236 }
2237
2238 /**
2239 * Checks that the given values, from array vals starting at offset 0,
2240 * are assignable to the given serializable object fields.
2241 * @throws ClassCastException if any value is not assignable
2242 */
2243 void checkObjectFieldValueTypes(Object obj, Object[] vals) {
2244 setObjFieldValues(obj, vals, true);
2245 }
2246
2247 /**
2248 * Sets the serializable object fields of object obj using values from
2249 * array vals starting at offset 0. The caller is responsible for
2250 * ensuring that obj is of the proper type; however, attempts to set a
2251 * field with a value of the wrong type will trigger an appropriate
2252 * ClassCastException.
2253 */
2254 void setObjFieldValues(Object obj, Object[] vals) {
2255 setObjFieldValues(obj, vals, false);
2256 }
2257
2258 private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
2259 if (obj == null) {
2260 throw new NullPointerException();
2261 }
2262 for (int i = numPrimFields; i < fields.length; i++) {
2263 long key = writeKeys[i];
2264 if (key == Unsafe.INVALID_FIELD_OFFSET) {
2265 continue; // discard value
2266 }
2267 switch (typeCodes[i]) {
2268 case 'L':
2269 case '[':
2270 Object val = vals[offsets[i]];
2271 if (val != null &&
2272 !types[i - numPrimFields].isInstance(val))
2273 {
2274 Field f = fields[i].getField();
2275 throw new ClassCastException(
2276 "cannot assign instance of " +
2277 val.getClass().getName() + " to field " +
2278 f.getDeclaringClass().getName() + "." +
2279 f.getName() + " of type " +
2280 f.getType().getName() + " in instance of " +
2281 obj.getClass().getName());
2282 }
2283 if (!dryRun)
2284 unsafe.putReference(obj, key, val);
2285 break;
2286
2287 default:
2288 throw new InternalError();
2289 }
2290 }
2291 }
2292 }
2293
2294 /**
2295 * Matches given set of serializable fields with serializable fields
2296 * described by the given local class descriptor, and returns a
2297 * FieldReflector instance capable of setting/getting values from the
2298 * subset of fields that match (non-matching fields are treated as filler,
2299 * for which get operations return default values and set operations
2300 * discard given values). Throws InvalidClassException if unresolvable
2301 * type conflicts exist between the two sets of fields.
2302 */
2303 private static FieldReflector getReflector(ObjectStreamField[] fields,
2304 ObjectStreamClass localDesc)
2305 throws InvalidClassException
2306 {
2307 // class irrelevant if no fields
2308 Class<?> cl = (localDesc != null && fields.length > 0) ?
2309 localDesc.cl : null;
2310 processQueue(Caches.reflectorsQueue, Caches.reflectors);
2311 FieldReflectorKey key = new FieldReflectorKey(cl, fields,
2312 Caches.reflectorsQueue);
2313 Reference<?> ref = Caches.reflectors.get(key);
2314 Object entry = null;
2315 if (ref != null) {
2316 entry = ref.get();
2317 }
2318 EntryFuture future = null;
2319 if (entry == null) {
2320 EntryFuture newEntry = new EntryFuture();
2321 Reference<?> newRef = new SoftReference<>(newEntry);
2322 do {
2323 if (ref != null) {
2324 Caches.reflectors.remove(key, ref);
2325 }
2326 ref = Caches.reflectors.putIfAbsent(key, newRef);
2327 if (ref != null) {
2328 entry = ref.get();
2329 }
2330 } while (ref != null && entry == null);
2331 if (entry == null) {
2332 future = newEntry;
2333 }
2334 }
2335
2336 if (entry instanceof FieldReflector) { // check common case first
2337 return (FieldReflector) entry;
2338 } else if (entry instanceof EntryFuture) {
2339 entry = ((EntryFuture) entry).get();
2340 } else if (entry == null) {
2341 try {
2342 entry = new FieldReflector(matchFields(fields, localDesc));
2343 } catch (Throwable th) {
2344 entry = th;
2345 }
2346 future.set(entry);
2347 Caches.reflectors.put(key, new SoftReference<>(entry));
2348 }
2349
2350 if (entry instanceof FieldReflector) {
2351 return (FieldReflector) entry;
2352 } else if (entry instanceof InvalidClassException) {
2353 throw (InvalidClassException) entry;
2354 } else if (entry instanceof RuntimeException) {
2355 throw (RuntimeException) entry;
2356 } else if (entry instanceof Error) {
2357 throw (Error) entry;
2358 } else {
2359 throw new InternalError("unexpected entry: " + entry);
2360 }
2361 }
2362
2363 /**
2364 * FieldReflector cache lookup key. Keys are considered equal if they
2365 * refer to the same class and equivalent field formats.
2366 */
2367 private static class FieldReflectorKey extends WeakReference<Class<?>> {
2368
2369 private final String[] sigs;
2370 private final int hash;
2371 private final boolean nullClass;
2372
2373 FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields,
2374 ReferenceQueue<Class<?>> queue)
2375 {
2376 super(cl, queue);
2377 nullClass = (cl == null);
2378 sigs = new String[2 * fields.length];
2379 for (int i = 0, j = 0; i < fields.length; i++) {
2380 ObjectStreamField f = fields[i];
2381 sigs[j++] = f.getName();
2382 sigs[j++] = f.getSignature();
2383 }
2384 hash = System.identityHashCode(cl) + Arrays.hashCode(sigs);
2385 }
2386
2387 public int hashCode() {
2388 return hash;
2389 }
2390
2391 public boolean equals(Object obj) {
2392 if (obj == this) {
2393 return true;
2394 }
2395
2396 if (obj instanceof FieldReflectorKey) {
2397 FieldReflectorKey other = (FieldReflectorKey) obj;
2398 Class<?> referent;
2399 return (nullClass ? other.nullClass
2400 : ((referent = get()) != null) &&
2401 (referent == other.get())) &&
2402 Arrays.equals(sigs, other.sigs);
2403 } else {
2404 return false;
2405 }
2406 }
2407 }
2408
2409 /**
2410 * Matches given set of serializable fields with serializable fields
2411 * obtained from the given local class descriptor (which contain bindings
2412 * to reflective Field objects). Returns list of ObjectStreamFields in
2413 * which each ObjectStreamField whose signature matches that of a local
2414 * field contains a Field object for that field; unmatched
2415 * ObjectStreamFields contain null Field objects. Shared/unshared settings
2416 * of the returned ObjectStreamFields also reflect those of matched local
2417 * ObjectStreamFields. Throws InvalidClassException if unresolvable type
2418 * conflicts exist between the two sets of fields.
2419 */
2420 private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
2421 ObjectStreamClass localDesc)
2422 throws InvalidClassException
2423 {
2424 ObjectStreamField[] localFields = (localDesc != null) ?
2425 localDesc.fields : NO_FIELDS;
2426
2427 /*
2428 * Even if fields == localFields, we cannot simply return localFields
2429 * here. In previous implementations of serialization,
2430 * ObjectStreamField.getType() returned Object.class if the
2431 * ObjectStreamField represented a non-primitive field and belonged to
2432 * a non-local class descriptor. To preserve this (questionable)
2433 * behavior, the ObjectStreamField instances returned by matchFields
2434 * cannot report non-primitive types other than Object.class; hence
2435 * localFields cannot be returned directly.
2436 */
2437
2438 ObjectStreamField[] matches = new ObjectStreamField[fields.length];
2439 for (int i = 0; i < fields.length; i++) {
2440 ObjectStreamField f = fields[i], m = null;
2441 for (int j = 0; j < localFields.length; j++) {
2442 ObjectStreamField lf = localFields[j];
2443 if (f.getName().equals(lf.getName())) {
2444 if ((f.isPrimitive() || lf.isPrimitive()) &&
2445 f.getTypeCode() != lf.getTypeCode())
2446 {
2447 throw new InvalidClassException(localDesc.name,
2448 "incompatible types for field " + f.getName());
2449 }
2450 if (lf.getField() != null) {
2451 m = new ObjectStreamField(
2452 lf.getField(), lf.isUnshared(), false);
2453 } else {
2454 m = new ObjectStreamField(
2455 lf.getName(), lf.getSignature(), lf.isUnshared());
2456 }
2457 }
2458 }
2459 if (m == null) {
2460 m = new ObjectStreamField(
2461 f.getName(), f.getSignature(), false);
2462 }
2463 m.setOffset(f.getOffset());
2464 matches[i] = m;
2465 }
2466 return matches;
2467 }
2468
2469 /**
2470 * Removes from the specified map any keys that have been enqueued
2471 * on the specified reference queue.
2472 */
2473 static void processQueue(ReferenceQueue<Class<?>> queue,
2474 ConcurrentMap<? extends
2475 WeakReference<Class<?>>, ?> map)
2476 {
2477 Reference<? extends Class<?>> ref;
2478 while((ref = queue.poll()) != null) {
2479 map.remove(ref);
2480 }
2481 }
2482
2483 /**
2484 * Weak key for Class objects.
2485 *
2486 **/
2487 static class WeakClassKey extends WeakReference<Class<?>> {
2488 /**
2489 * saved value of the referent's identity hash code, to maintain
2490 * a consistent hash code after the referent has been cleared
2491 */
2492 private final int hash;
2493
2494 /**
2495 * Create a new WeakClassKey to the given object, registered
2496 * with a queue.
2497 */
2498 WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
2499 super(cl, refQueue);
2500 hash = System.identityHashCode(cl);
2501 }
2502
2503 /**
2504 * Returns the identity hash code of the original referent.
2505 */
2506 public int hashCode() {
2507 return hash;
2508 }
2509
2510 /**
2511 * Returns true if the given object is this identical
2512 * WeakClassKey instance, or, if this object's referent has not
2513 * been cleared, if the given object is another WeakClassKey
2514 * instance with the identical non-null referent as this one.
2515 */
2516 public boolean equals(Object obj) {
2517 if (obj == this) {
2518 return true;
2519 }
2520
2521 if (obj instanceof WeakClassKey) {
2522 Object referent = get();
2523 return (referent != null) &&
2524 (referent == ((WeakClassKey) obj).get());
2525 } else {
2526 return false;
2527 }
2528 }
2529 }
2530
2531 /** Record specific support for retrieving and binding stream field values. */
2532 static final class RecordSupport {
2533
2534 /** Binds the given stream field values to the given method handle. */
2535 @SuppressWarnings("preview")
2536 static MethodHandle bindCtrValues(MethodHandle ctrMH,
2537 ObjectStreamClass desc,
2538 ObjectInputStream.FieldValues fieldValues) {
2539 RecordComponent[] recordComponents;
2540 try {
2541 Class<?> cls = desc.forClass();
2542 PrivilegedExceptionAction<RecordComponent[]> pa = cls::getRecordComponents;
2543 recordComponents = AccessController.doPrivileged(pa);
2544 } catch (PrivilegedActionException e) {
2545 throw new InternalError(e.getCause());
2546 }
2547
2548 Object[] args = new Object[recordComponents.length];
2549 for (int i = 0; i < recordComponents.length; i++) {
2550 String name = recordComponents[i].getName();
2551 Class<?> type= recordComponents[i].getType();
2552 Object o = streamFieldValue(name, type, desc, fieldValues);
2553 args[i] = o;
2554 }
2555
2556 return MethodHandles.insertArguments(ctrMH, 0, args);
2557 }
2558
2559 /** Returns the number of primitive fields for the given descriptor. */
2560 private static int numberPrimValues(ObjectStreamClass desc) {
2561 ObjectStreamField[] fields = desc.getFields();
2562 int primValueCount = 0;
2563 for (int i = 0; i < fields.length; i++) {
2564 if (fields[i].isPrimitive())
2565 primValueCount++;
2566 else
2567 break; // can be no more
2568 }
2569 return primValueCount;
2570 }
2571
2572 /** Returns the default value for the given type. */
2573 private static Object defaultValueFor(Class<?> pType) {
2574 if (pType == Integer.TYPE)
2575 return 0;
2576 else if (pType == Byte.TYPE)
2577 return (byte)0;
2578 else if (pType == Long.TYPE)
2579 return 0L;
2580 else if (pType == Float.TYPE)
2581 return 0.0f;
2582 else if (pType == Double.TYPE)
2583 return 0.0d;
2584 else if (pType == Short.TYPE)
2585 return (short)0;
2586 else if (pType == Character.TYPE)
2587 return '\u0000';
2588 else if (pType == Boolean.TYPE)
2589 return false;
2590 else
2591 return null;
2592 }
2593
2594 /**
2595 * Returns the stream field value for the given name. The default value
2596 * for the given type is returned if the field value is absent.
2597 */
2598 private static Object streamFieldValue(String pName,
2599 Class<?> pType,
2600 ObjectStreamClass desc,
2601 ObjectInputStream.FieldValues fieldValues) {
2602 ObjectStreamField[] fields = desc.getFields();
2603
2604 for (int i = 0; i < fields.length; i++) {
2605 ObjectStreamField f = fields[i];
2606 String fName = f.getName();
2607 if (!fName.equals(pName))
2608 continue;
2609
2610 Class<?> fType = f.getField().getType();
2611 if (!pType.isAssignableFrom(fType))
2612 throw new InternalError(fName + " unassignable, pType:" + pType + ", fType:" + fType);
2613
2614 if (f.isPrimitive()) {
2615 if (pType == Integer.TYPE)
2616 return Bits.getInt(fieldValues.primValues, f.getOffset());
2617 else if (fType == Byte.TYPE)
2618 return fieldValues.primValues[f.getOffset()];
2619 else if (fType == Long.TYPE)
2620 return Bits.getLong(fieldValues.primValues, f.getOffset());
2621 else if (fType == Float.TYPE)
2622 return Bits.getFloat(fieldValues.primValues, f.getOffset());
2623 else if (fType == Double.TYPE)
2624 return Bits.getDouble(fieldValues.primValues, f.getOffset());
2625 else if (fType == Short.TYPE)
2626 return Bits.getShort(fieldValues.primValues, f.getOffset());
2627 else if (fType == Character.TYPE)
2628 return Bits.getChar(fieldValues.primValues, f.getOffset());
2629 else if (fType == Boolean.TYPE)
2630 return Bits.getBoolean(fieldValues.primValues, f.getOffset());
2631 else
2632 throw new InternalError("Unexpected type: " + fType);
2633 } else { // reference
2634 return fieldValues.objValues[i - numberPrimValues(desc)];
2635 }
2636 }
2637
2638 return defaultValueFor(pType);
2639 }
2640 }
2641 }