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