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