Home » openjdk-7 » java » io » [javadoc | source]

    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   }

Home » openjdk-7 » java » io » [javadoc | source]