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