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