src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java

Mon, 16 Oct 2017 15:59:03 +0800

author
aoqi
date
Mon, 16 Oct 2017 15:59:03 +0800
changeset 1022
6081f57a0021
parent 748
6845b95cba6b
child 1550
b9597bbca222
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1998, 2014, 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  * Licensed Materials - Property of IBM
    27  * RMI-IIOP v1.0
    28  * Copyright IBM Corp. 1998 2012  All Rights Reserved
    29  *
    30  */
    32 package com.sun.corba.se.impl.io;
    34 import java.security.MessageDigest;
    35 import java.security.NoSuchAlgorithmException;
    36 import java.security.DigestOutputStream;
    37 import java.security.AccessController;
    38 import java.security.PrivilegedExceptionAction;
    39 import java.security.PrivilegedActionException;
    40 import java.security.PrivilegedAction;
    42 import java.lang.reflect.Modifier;
    43 import java.lang.reflect.Array;
    44 import java.lang.reflect.Field;
    45 import java.lang.reflect.Member;
    46 import java.lang.reflect.Method;
    47 import java.lang.reflect.Constructor;
    48 import java.lang.reflect.Proxy;
    49 import java.lang.reflect.InvocationTargetException;
    51 import java.io.IOException;
    52 import java.io.DataOutputStream;
    53 import java.io.ByteArrayOutputStream;
    54 import java.io.InvalidClassException;
    55 import java.io.Externalizable;
    56 import java.io.Serializable;
    58 import java.util.Arrays;
    59 import java.util.Comparator;
    61 import com.sun.corba.se.impl.util.RepositoryId;
    63 import org.omg.CORBA.ValueMember;
    65 import sun.corba.Bridge;
    67 /**
    68  * A ObjectStreamClass describes a class that can be serialized to a stream
    69  * or a class that was serialized to a stream.  It contains the name
    70  * and the serialVersionUID of the class.
    71  * <br>
    72  * The ObjectStreamClass for a specific class loaded in this Java VM can
    73  * be found using the lookup method.
    74  *
    75  * @author  Roger Riggs
    76  * @since   JDK1.1
    77  */
    78 public class ObjectStreamClass implements java.io.Serializable {
    79     private static final boolean DEBUG_SVUID = false ;
    81     public static final long kDefaultUID = -1;
    83     private static Object noArgsList[] = {};
    84     private static Class<?> noTypesList[] = {};
    86     /** true if represents enum type */
    87     private boolean isEnum;
    89     private static final Bridge bridge =
    90         AccessController.doPrivileged(
    91             new PrivilegedAction<Bridge>() {
    92                 public Bridge run() {
    93                     return Bridge.get() ;
    94                 }
    95             }
    96         ) ;
    98     /** Find the descriptor for a class that can be serialized.  Null
    99      * is returned if the specified class does not implement
   100      * java.io.Serializable or java.io.Externalizable.
   101      */
   102     static final ObjectStreamClass lookup(Class<?> cl)
   103     {
   104         ObjectStreamClass desc = lookupInternal(cl);
   105         if (desc.isSerializable() || desc.isExternalizable())
   106             return desc;
   107         return null;
   108     }
   110     /*
   111      * Find the class descriptor for the specified class.
   112      * Package access only so it can be called from ObjectIn/OutStream.
   113      */
   114     static ObjectStreamClass lookupInternal(Class<?> cl)
   115     {
   116         /* Synchronize on the hashtable so no two threads will do
   117          * this at the same time.
   118          */
   119         ObjectStreamClass desc = null;
   120         synchronized (descriptorFor) {
   121             /* Find the matching descriptor if it already known */
   122             desc = findDescriptorFor(cl);
   123             if (desc == null) {
   124                 /* Check if it's serializable */
   125                 boolean serializable = Serializable.class.isAssignableFrom(cl);
   127                 /* If the class is only Serializable,
   128                  * lookup the descriptor for the superclass.
   129                  */
   130                 ObjectStreamClass superdesc = null;
   131                 if (serializable) {
   132                     Class<?> superclass = cl.getSuperclass();
   133                     if (superclass != null)
   134                         superdesc = lookup(superclass);
   135                 }
   137                 /* Check if its' externalizable.
   138                  * If it's Externalizable, clear the serializable flag.
   139                  * Only one or the other may be set in the protocol.
   140                  */
   141                 boolean externalizable = false;
   142                 if (serializable) {
   143                     externalizable =
   144                         ((superdesc != null) && superdesc.isExternalizable()) ||
   145                         Externalizable.class.isAssignableFrom(cl);
   146                     if (externalizable) {
   147                         serializable = false;
   148                     }
   149                 }
   151                 /* Create a new version descriptor,
   152                  * it put itself in the known table.
   153                  */
   154                 desc = new ObjectStreamClass(cl, superdesc,
   155                                              serializable, externalizable);
   156             }
   157             // Must always call init.  See bug 4488137.  This code was
   158             // incorrectly changed to return immediately on a non-null
   159             // cache result.  That allowed threads to gain access to
   160             // unintialized instances.
   161             //
   162             // History: Note, the following init() call was originally within
   163             // the synchronization block, as it currently is now. Later, the
   164             // init() call was moved outside the synchronization block, and
   165             // the init() method used a private member variable lock, to
   166             // avoid performance problems. See bug 4165204. But that lead to
   167             // a deadlock situation, see bug 5104239. Hence, the init() method
   168             // has now been moved back into the synchronization block. The
   169             // right approach to solving these problems would be to rewrite
   170             // this class, based on the latest java.io.ObjectStreamClass.
   171             desc.init();
   172         }
   173         return desc;
   174     }
   176     /**
   177      * The name of the class described by this descriptor.
   178      */
   179     public final String getName() {
   180         return name;
   181     }
   183     /**
   184      * Return the serialVersionUID for this class.
   185      * The serialVersionUID defines a set of classes all with the same name
   186      * that have evolved from a common root class and agree to be serialized
   187      * and deserialized using a common format.
   188      */
   189     public static final long getSerialVersionUID( java.lang.Class<?> clazz) {
   190         ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
   191         if( theosc != null )
   192         {
   193                 return theosc.getSerialVersionUID( );
   194         }
   195         return 0;
   196     }
   198     /**
   199      * Return the serialVersionUID for this class.
   200      * The serialVersionUID defines a set of classes all with the same name
   201      * that have evolved from a common root class and agree to be serialized
   202      * and deserialized using a common format.
   203      */
   204     public final long getSerialVersionUID() {
   205         return suid;
   206     }
   208     /**
   209      * Return the serialVersionUID string for this class.
   210      * The serialVersionUID defines a set of classes all with the same name
   211      * that have evolved from a common root class and agree to be serialized
   212      * and deserialized using a common format.
   213      */
   214     public final String getSerialVersionUIDStr() {
   215         if (suidStr == null)
   216             suidStr = Long.toHexString(suid).toUpperCase();
   217         return suidStr;
   218     }
   220     /**
   221      * Return the actual (computed) serialVersionUID for this class.
   222      */
   223     public static final long getActualSerialVersionUID( java.lang.Class<?> clazz )
   224     {
   225         ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
   226         if( theosc != null )
   227         {
   228                 return theosc.getActualSerialVersionUID( );
   229         }
   230         return 0;
   231     }
   233     /**
   234      * Return the actual (computed) serialVersionUID for this class.
   235      */
   236     public final long getActualSerialVersionUID() {
   237         return actualSuid;
   238     }
   240     /**
   241      * Return the actual (computed) serialVersionUID for this class.
   242      */
   243     public final String getActualSerialVersionUIDStr() {
   244         if (actualSuidStr == null)
   245             actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
   246         return actualSuidStr;
   247     }
   249     /**
   250      * Return the class in the local VM that this version is mapped to.
   251      * Null is returned if there is no corresponding local class.
   252      */
   253     public final Class<?> forClass() {
   254         return ofClass;
   255     }
   257     /**
   258      * Return an array of the fields of this serializable class.
   259      * @return an array containing an element for each persistent
   260      * field of this class. Returns an array of length zero if
   261      * there are no fields.
   262      * @since JDK1.2
   263      */
   264     public ObjectStreamField[] getFields() {
   265         // Return a copy so the caller can't change the fields.
   266         if (fields.length > 0) {
   267             ObjectStreamField[] dup = new ObjectStreamField[fields.length];
   268             System.arraycopy(fields, 0, dup, 0, fields.length);
   269             return dup;
   270         } else {
   271             return fields;
   272         }
   273     }
   275     public boolean hasField(ValueMember field)
   276     {
   277         try {
   278             for (int i = 0; i < fields.length; i++) {
   279                 if (fields[i].getName().equals(field.name)) {
   280                     if (fields[i].getSignature().equals(
   281                         ValueUtility.getSignature(field)))
   282                         return true;
   283                 }
   284             }
   285         } catch (Exception exc) {
   286             // Ignore this; all we want to do is return false
   287             // Note that ValueUtility.getSignature can throw checked exceptions.
   288         }
   290         return false;
   291     }
   293     /* Avoid unnecessary allocations. */
   294     final ObjectStreamField[] getFieldsNoCopy() {
   295         return fields;
   296     }
   298     /**
   299      * Get the field of this class by name.
   300      * @return The ObjectStreamField object of the named field or null if there
   301      * is no such named field.
   302      */
   303     public final ObjectStreamField getField(String name) {
   304         /* Binary search of fields by name.
   305          */
   306         for (int i = fields.length-1; i >= 0; i--) {
   307             if (name.equals(fields[i].getName())) {
   308                 return fields[i];
   309             }
   310         }
   311         return null;
   312     }
   314     public Serializable writeReplace(Serializable value) {
   315         if (writeReplaceObjectMethod != null) {
   316             try {
   317                 return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
   318             } catch(Throwable t) {
   319                 throw new RuntimeException(t);
   320             }
   321         }
   322         else return value;
   323     }
   325     public Object readResolve(Object value) {
   326         if (readResolveObjectMethod != null) {
   327             try {
   328                 return readResolveObjectMethod.invoke(value,noArgsList);
   329             } catch(Throwable t) {
   330                 throw new RuntimeException(t);
   331             }
   332         }
   333         else return value;
   334     }
   336     /**
   337      * Return a string describing this ObjectStreamClass.
   338      */
   339     public final String toString() {
   340         StringBuffer sb = new StringBuffer();
   342         sb.append(name);
   343         sb.append(": static final long serialVersionUID = ");
   344         sb.append(Long.toString(suid));
   345         sb.append("L;");
   346         return sb.toString();
   347     }
   349     /*
   350      * Create a new ObjectStreamClass from a loaded class.
   351      * Don't call this directly, call lookup instead.
   352      */
   353     private ObjectStreamClass(java.lang.Class<?> cl, ObjectStreamClass superdesc,
   354                               boolean serial, boolean extern)
   355     {
   356         ofClass = cl;           /* created from this class */
   358         if (Proxy.isProxyClass(cl)) {
   359             forProxyClass = true;
   360         }
   362         name = cl.getName();
   363         isEnum = Enum.class.isAssignableFrom(cl);
   364         superclass = superdesc;
   365         serializable = serial;
   366         if (!forProxyClass) {
   367             // proxy classes are never externalizable
   368             externalizable = extern;
   369         }
   371         /*
   372          * Enter this class in the table of known descriptors.
   373          * Otherwise, when the fields are read it may recurse
   374          * trying to find the descriptor for itself.
   375          */
   376         insertDescriptorFor(this);
   378         /*
   379          * The remainder of initialization occurs in init(), which is called
   380          * after the lock on the global class descriptor table has been
   381          * released.
   382          */
   383     }
   385     private static final class PersistentFieldsValue
   386             extends ClassValue<ObjectStreamField[]> {
   387         PersistentFieldsValue() { }
   389         protected ObjectStreamField[] computeValue(Class<?> type) {
   390             try {
   391                 Field pf = type.getDeclaredField("serialPersistentFields");
   392                 int mods = pf.getModifiers();
   393                 if (Modifier.isPrivate(mods) && Modifier.isStatic(mods) &&
   394                         Modifier.isFinal(mods)) {
   395                     pf.setAccessible(true);
   396                     java.io.ObjectStreamField[] fields =
   397                         (java.io.ObjectStreamField[])pf.get(type);
   398                     return translateFields(fields);
   399                 }
   400             } catch (NoSuchFieldException | IllegalAccessException |
   401                     IllegalArgumentException | ClassCastException e) {
   402             }
   403             return null;
   404         }
   406         private static ObjectStreamField[] translateFields(
   407             java.io.ObjectStreamField[] fields) {
   408             ObjectStreamField[] translation =
   409                 new ObjectStreamField[fields.length];
   410             for (int i = 0; i < fields.length; i++) {
   411                 translation[i] = new ObjectStreamField(fields[i].getName(),
   412                         fields[i].getType());
   413             }
   414             return translation;
   415         }
   416     }
   418     private static final PersistentFieldsValue persistentFieldsValue =
   419         new PersistentFieldsValue();
   421     /*
   422      * Initialize class descriptor.  This method is only invoked on class
   423      * descriptors created via calls to lookupInternal().  This method is kept
   424      * separate from the ObjectStreamClass constructor so that lookupInternal
   425      * does not have to hold onto a global class descriptor table lock while the
   426      * class descriptor is being initialized (see bug 4165204).
   427      */
   430     private void init() {
   431       synchronized (lock) {
   433         // See description at definition of initialized.
   434         if (initialized)
   435             return;
   437         final Class<?> cl = ofClass;
   439         if (!serializable ||
   440             externalizable ||
   441             forProxyClass ||
   442             name.equals("java.lang.String")){
   443             fields = NO_FIELDS;
   444         } else if (serializable) {
   445             /* Ask for permission to override field access checks.
   446              */
   447             AccessController.doPrivileged(new PrivilegedAction() {
   448                 public Object run() {
   449                 /* Fill in the list of persistent fields.
   450                  * If it is declared, use the declared serialPersistentFields.
   451                  * Otherwise, extract the fields from the class itself.
   452                  */
   453                     fields = persistentFieldsValue.get(cl);
   455                 if (fields == null) {
   456                     /* Get all of the declared fields for this
   457                      * Class. setAccessible on all fields so they
   458                      * can be accessed later.  Create a temporary
   459                      * ObjectStreamField array to hold each
   460                      * non-static, non-transient field. Then copy the
   461                      * temporary array into an array of the correct
   462                      * size once the number of fields is known.
   463                      */
   464                     Field[] actualfields = cl.getDeclaredFields();
   466                     int numFields = 0;
   467                     ObjectStreamField[] tempFields =
   468                         new ObjectStreamField[actualfields.length];
   469                     for (int i = 0; i < actualfields.length; i++) {
   470                         Field fld = actualfields[i] ;
   471                         int modifiers = fld.getModifiers();
   472                         if (!Modifier.isStatic(modifiers) &&
   473                             !Modifier.isTransient(modifiers)) {
   474                             fld.setAccessible(true) ;
   475                             tempFields[numFields++] = new ObjectStreamField(fld);
   476                         }
   477                     }
   479                     fields = new ObjectStreamField[numFields];
   480                     System.arraycopy(tempFields, 0, fields, 0, numFields);
   482                 } else {
   483                     // For each declared persistent field, look for an actual
   484                     // reflected Field. If there is one, make sure it's the correct
   485                     // type and cache it in the ObjectStreamClass for that field.
   486                     for (int j = fields.length-1; j >= 0; j--) {
   487                         try {
   488                             Field reflField = cl.getDeclaredField(fields[j].getName());
   489                             if (fields[j].getType() == reflField.getType()) {
   490                                 reflField.setAccessible(true);
   491                                 fields[j].setField(reflField);
   492                             }
   493                         } catch (NoSuchFieldException e) {
   494                             // Nothing to do
   495                         }
   496                     }
   497                 }
   498                 return null;
   499             }
   500             });
   502             if (fields.length > 1)
   503                 Arrays.sort(fields);
   505             /* Set up field data for use while writing using the API api. */
   506             computeFieldInfo();
   507         }
   509         /* Get the serialVersionUID from the class.
   510          * It uses the access override mechanism so make sure
   511          * the field objects is only used here.
   512          *
   513          * NonSerializable classes have a serialVerisonUID of 0L.
   514          */
   515          if (isNonSerializable() || isEnum) {
   516              suid = 0L;
   517          } else {
   518              // Lookup special Serializable members using reflection.
   519              AccessController.doPrivileged(new PrivilegedAction() {
   520                 public Object run() {
   521                 if (forProxyClass) {
   522                     // proxy classes always have serialVersionUID of 0L
   523                     suid = 0L;
   524                 } else {
   525                     try {
   526                         final Field f = cl.getDeclaredField("serialVersionUID");
   527                         int mods = f.getModifiers();
   528                         // SerialBug 5:  static final SUID should be read
   529                         if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) {
   530                             f.setAccessible(true);
   531                             suid = f.getLong(cl);
   532                             // SerialBug 2: should be computed after writeObject
   533                             // actualSuid = computeStructuralUID(cl);
   534                         } else {
   535                             suid = _computeSerialVersionUID(cl);
   536                             // SerialBug 2: should be computed after writeObject
   537                             // actualSuid = computeStructuralUID(cl);
   538                         }
   539                     } catch (NoSuchFieldException ex) {
   540                         suid = _computeSerialVersionUID(cl);
   541                         // SerialBug 2: should be computed after writeObject
   542                         // actualSuid = computeStructuralUID(cl);
   543                     } catch (IllegalAccessException ex) {
   544                         suid = _computeSerialVersionUID(cl);
   545                     }
   546                 }
   548                 writeReplaceObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
   549                     "writeReplace", noTypesList, Object.class);
   551                 readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
   552                     "readResolve", noTypesList, Object.class);
   554                 if (externalizable)
   555                     cons = getExternalizableConstructor(cl) ;
   556                 else
   557                     cons = getSerializableConstructor(cl) ;
   559                 if (serializable && !forProxyClass) {
   560                     /* Look for the writeObject method
   561                      * Set the accessible flag on it here. ObjectOutputStream
   562                      * will call it as necessary.
   563                      */
   564                     writeObjectMethod = getPrivateMethod( cl, "writeObject",
   565                         new Class<?>[] { java.io.ObjectOutputStream.class }, Void.TYPE ) ;
   566                     readObjectMethod = getPrivateMethod( cl, "readObject",
   567                         new Class<?>[] { java.io.ObjectInputStream.class }, Void.TYPE ) ;
   568                 }
   569                 return null;
   570             }
   571           });
   572         }
   574         // This call depends on a lot of information computed above!
   575         actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);
   577         // If we have a write object method, precompute the
   578         // RMI-IIOP stream format version 2 optional data
   579         // repository ID.
   580         if (hasWriteObject())
   581             rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId();
   583         // This must be done last.
   584         initialized = true;
   585       }
   586     }
   588     /**
   589      * Returns non-static private method with given signature defined by given
   590      * class, or null if none found.  Access checks are disabled on the
   591      * returned method (if any).
   592      */
   593     private static Method getPrivateMethod(Class<?> cl, String name,
   594                                            Class<?>[] argTypes,
   595                                            Class<?> returnType)
   596     {
   597         try {
   598             Method meth = cl.getDeclaredMethod(name, argTypes);
   599             meth.setAccessible(true);
   600             int mods = meth.getModifiers();
   601             return ((meth.getReturnType() == returnType) &&
   602                     ((mods & Modifier.STATIC) == 0) &&
   603                     ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
   604         } catch (NoSuchMethodException ex) {
   605             return null;
   606         }
   607     }
   609     // Specific to RMI-IIOP
   610     /**
   611      * Java to IDL ptc-02-01-12 1.5.1
   612      *
   613      * "The rep_id string passed to the start_value method must be
   614      * 'RMI:org.omg.custom.class:hashcode:suid' where class is the
   615      * fully-qualified name of the class whose writeObject method
   616      * is being invoked and hashcode and suid are the class's hashcode
   617      * and SUID."
   618      */
   619     private String computeRMIIIOPOptionalDataRepId() {
   621         StringBuffer sbuf = new StringBuffer("RMI:org.omg.custom.");
   622         sbuf.append(RepositoryId.convertToISOLatin1(this.getName()));
   623         sbuf.append(':');
   624         sbuf.append(this.getActualSerialVersionUIDStr());
   625         sbuf.append(':');
   626         sbuf.append(this.getSerialVersionUIDStr());
   628         return sbuf.toString();
   629     }
   631     /**
   632      * This will return null if there is no writeObject method.
   633      */
   634     public final String getRMIIIOPOptionalDataRepId() {
   635         return rmiiiopOptionalDataRepId;
   636     }
   638     /*
   639      * Create an empty ObjectStreamClass for a class about to be read.
   640      * This is separate from read so ObjectInputStream can assign the
   641      * wire handle early, before any nested ObjectStreamClass might
   642      * be read.
   643      */
   644     ObjectStreamClass(String n, long s) {
   645         name = n;
   646         suid = s;
   647         superclass = null;
   648     }
   651     /*
   652      * Set the class this version descriptor matches.
   653      * The base class name and serializable hash must match.
   654      * Fill in the reflected Fields that will be used
   655      * for reading.
   656      */
   657     final void setClass(Class<?> cl) throws InvalidClassException {
   659         if (cl == null) {
   660             localClassDesc = null;
   661             ofClass = null;
   662             computeFieldInfo();
   663             return;
   664         }
   666         localClassDesc = lookupInternal(cl);
   667         if (localClassDesc == null)
   668             // XXX I18N, logging needed
   669             throw new InvalidClassException(cl.getName(),
   670                                             "Local class not compatible");
   671         if (suid != localClassDesc.suid) {
   673             /* Check for exceptional cases that allow mismatched suid. */
   675             /* Allow adding Serializable or Externalizable
   676              * to a later release of the class.
   677              */
   678             boolean addedSerialOrExtern =
   679                 isNonSerializable() || localClassDesc.isNonSerializable();
   681             /* Disregard the serialVersionUID of an array
   682              * when name and cl.Name differ. If resolveClass() returns
   683              * an array with a different package name,
   684              * the serialVersionUIDs will not match since the fully
   685              * qualified array class is used in the
   686              * computation of the array's serialVersionUID. There is
   687              * no way to set a permanent serialVersionUID for an array type.
   688              */
   690             boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));
   692             if (! arraySUID && ! addedSerialOrExtern ) {
   693                 // XXX I18N, logging needed
   694                 throw new InvalidClassException(cl.getName(),
   695                                                 "Local class not compatible:" +
   696                                                 " stream classdesc serialVersionUID=" + suid +
   697                                                 " local class serialVersionUID=" + localClassDesc.suid);
   698             }
   699         }
   701         /* compare the class names, stripping off package names. */
   702         if (! compareClassNames(name, cl.getName(), '.'))
   703             // XXX I18N, logging needed
   704             throw new InvalidClassException(cl.getName(),
   705                          "Incompatible local class name. " +
   706                          "Expected class name compatible with " +
   707                          name);
   709         /*
   710          * Test that both implement either serializable or externalizable.
   711          */
   713         // The next check is more generic, since it covers the
   714         // Proxy case, the JDK 1.3 serialization code has
   715         // both checks
   716         //if ((serializable && localClassDesc.externalizable) ||
   717         //    (externalizable && localClassDesc.serializable))
   718         //    throw new InvalidClassException(localCl.getName(),
   719         //            "Serializable is incompatible with Externalizable");
   721         if ((serializable != localClassDesc.serializable) ||
   722             (externalizable != localClassDesc.externalizable) ||
   723             (!serializable && !externalizable))
   725             // XXX I18N, logging needed
   726             throw new InvalidClassException(cl.getName(),
   727                                             "Serialization incompatible with Externalization");
   729         /* Set up the reflected Fields in the class where the value of each
   730          * field in this descriptor should be stored.
   731          * Each field in this ObjectStreamClass (the source) is located (by
   732          * name) in the ObjectStreamClass of the class(the destination).
   733          * In the usual (non-versioned case) the field is in both
   734          * descriptors and the types match, so the reflected Field is copied.
   735          * If the type does not match, a InvalidClass exception is thrown.
   736          * If the field is not present in the class, the reflected Field
   737          * remains null so the field will be read but discarded.
   738          * If extra fields are present in the class they are ignored. Their
   739          * values will be set to the default value by the object allocator.
   740          * Both the src and dest field list are sorted by type and name.
   741          */
   743         ObjectStreamField[] destfield =
   744             (ObjectStreamField[])localClassDesc.fields;
   745         ObjectStreamField[] srcfield =
   746             (ObjectStreamField[])fields;
   748         int j = 0;
   749     nextsrc:
   750         for (int i = 0; i < srcfield.length; i++ ) {
   751             /* Find this field in the dest*/
   752             for (int k = j; k < destfield.length; k++) {
   753                 if (srcfield[i].getName().equals(destfield[k].getName())) {
   754                     /* found match */
   755                     if (srcfield[i].isPrimitive() &&
   756                         !srcfield[i].typeEquals(destfield[k])) {
   757                         // XXX I18N, logging needed
   758                         throw new InvalidClassException(cl.getName(),
   759                                                         "The type of field " +
   760                                                         srcfield[i].getName() +
   761                                                         " of class " + name +
   762                                                         " is incompatible.");
   763                     }
   765                     /* Skip over any fields in the dest that are not in the src */
   766                     j = k;
   768                     srcfield[i].setField(destfield[j].getField());
   769                     // go on to the next source field
   770                     continue nextsrc;
   771                 }
   772             }
   773         }
   775         /* Set up field data for use while reading from the input stream. */
   776         computeFieldInfo();
   778         /* Remember the class this represents */
   779         ofClass = cl;
   781         /* get the cache of these methods from the local class
   782          * implementation.
   783          */
   784         readObjectMethod = localClassDesc.readObjectMethod;
   785         readResolveObjectMethod = localClassDesc.readResolveObjectMethod;
   786     }
   788     /* Compare the base class names of streamName and localName.
   789      *
   790      * @return  Return true iff the base class name compare.
   791      * @parameter streamName    Fully qualified class name.
   792      * @parameter localName     Fully qualified class name.
   793      * @parameter pkgSeparator  class names use either '.' or '/'.
   794      *
   795      * Only compare base class name to allow package renaming.
   796      */
   797     static boolean compareClassNames(String streamName,
   798                                      String localName,
   799                                      char pkgSeparator) {
   800         /* compare the class names, stripping off package names. */
   801         int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
   802         if (streamNameIndex < 0)
   803             streamNameIndex = 0;
   805         int localNameIndex = localName.lastIndexOf(pkgSeparator);
   806         if (localNameIndex < 0)
   807             localNameIndex = 0;
   809         return streamName.regionMatches(false, streamNameIndex,
   810                                         localName, localNameIndex,
   811                                         streamName.length() - streamNameIndex);
   812     }
   814     /*
   815      * Compare the types of two class descriptors.
   816      * They match if they have the same class name and suid
   817      */
   818     final boolean typeEquals(ObjectStreamClass other) {
   819         return (suid == other.suid) &&
   820             compareClassNames(name, other.name, '.');
   821     }
   823     /*
   824      * Return the superclass descriptor of this descriptor.
   825      */
   826     final void setSuperclass(ObjectStreamClass s) {
   827         superclass = s;
   828     }
   830     /*
   831      * Return the superclass descriptor of this descriptor.
   832      */
   833     final ObjectStreamClass getSuperclass() {
   834         return superclass;
   835     }
   837     /**
   838      * Return whether the class has a readObject method
   839      */
   840     final boolean hasReadObject() {
   841         return readObjectMethod != null;
   842     }
   844     /*
   845      * Return whether the class has a writeObject method
   846      */
   847     final boolean hasWriteObject() {
   848         return writeObjectMethod != null ;
   849     }
   851     /**
   852      * Returns when or not this class should be custom
   853      * marshaled (use chunking).  This should happen if
   854      * it is Externalizable OR if it or
   855      * any of its superclasses has a writeObject method,
   856      */
   857     final boolean isCustomMarshaled() {
   858         return (hasWriteObject() || isExternalizable())
   859             || (superclass != null && superclass.isCustomMarshaled());
   860     }
   862     /*
   863      * Return true if all instances of 'this' Externalizable class
   864      * are written in block-data mode from the stream that 'this' was read
   865      * from. <p>
   866      *
   867      * In JDK 1.1, all Externalizable instances are not written
   868      * in block-data mode.
   869      * In JDK 1.2, all Externalizable instances, by default, are written
   870      * in block-data mode and the Externalizable instance is terminated with
   871      * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
   872      * instances.
   873      *
   874      * IMPLEMENTATION NOTE:
   875      *   This should have been a mode maintained per stream; however,
   876      *   for compatibility reasons, it was only possible to record
   877      *   this change per class. All Externalizable classes within
   878      *   a given stream should either have this mode enabled or
   879      *   disabled. This is enforced by not allowing the PROTOCOL_VERSION
   880      *   of a stream to he changed after any objects have been written.
   881      *
   882      * @see ObjectOutputStream#useProtocolVersion
   883      * @see ObjectStreamConstants#PROTOCOL_VERSION_1
   884      * @see ObjectStreamConstants#PROTOCOL_VERSION_2
   885      *
   886      * @since JDK 1.2
   887      */
   888     boolean hasExternalizableBlockDataMode() {
   889         return hasExternalizableBlockData;
   890     }
   892     /**
   893      * Creates a new instance of the represented class.  If the class is
   894      * externalizable, invokes its public no-arg constructor; otherwise, if the
   895      * class is serializable, invokes the no-arg constructor of the first
   896      * non-serializable superclass.  Throws UnsupportedOperationException if
   897      * this class descriptor is not associated with a class, if the associated
   898      * class is non-serializable or if the appropriate no-arg constructor is
   899      * inaccessible/unavailable.
   900      */
   901     Object newInstance()
   902         throws InstantiationException, InvocationTargetException,
   903                UnsupportedOperationException
   904     {
   905         if (cons != null) {
   906             try {
   907                 return cons.newInstance(new Object[0]);
   908             } catch (IllegalAccessException ex) {
   909                 // should not occur, as access checks have been suppressed
   910                 InternalError ie = new InternalError();
   911                 ie.initCause( ex ) ;
   912                 throw ie ;
   913             }
   914         } else {
   915             throw new UnsupportedOperationException();
   916         }
   917     }
   919     /**
   920      * Returns public no-arg constructor of given class, or null if none found.
   921      * Access checks are disabled on the returned constructor (if any), since
   922      * the defining class may still be non-public.
   923      */
   924     private static Constructor getExternalizableConstructor(Class<?> cl) {
   925         try {
   926             Constructor cons = cl.getDeclaredConstructor(new Class<?>[0]);
   927             cons.setAccessible(true);
   928             return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
   929                 cons : null;
   930         } catch (NoSuchMethodException ex) {
   931             return null;
   932         }
   933     }
   935     /**
   936      * Returns subclass-accessible no-arg constructor of first non-serializable
   937      * superclass, or null if none found.  Access checks are disabled on the
   938      * returned constructor (if any).
   939      */
   940     private static Constructor getSerializableConstructor(Class<?> cl) {
   941         Class<?> initCl = cl;
   942         while (Serializable.class.isAssignableFrom(initCl)) {
   943             if ((initCl = initCl.getSuperclass()) == null) {
   944                 return null;
   945             }
   946         }
   947         try {
   948             Constructor cons = initCl.getDeclaredConstructor(new Class<?>[0]);
   949             int mods = cons.getModifiers();
   950             if ((mods & Modifier.PRIVATE) != 0 ||
   951                 ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
   952                  !packageEquals(cl, initCl)))
   953             {
   954                 return null;
   955             }
   956             cons = bridge.newConstructorForSerialization(cl, cons);
   957             cons.setAccessible(true);
   958             return cons;
   959         } catch (NoSuchMethodException ex) {
   960             return null;
   961         }
   962     }
   964     /*
   965      * Return the ObjectStreamClass of the local class this one is based on.
   966      */
   967     final ObjectStreamClass localClassDescriptor() {
   968         return localClassDesc;
   969     }
   971     /*
   972      * Get the Serializability of the class.
   973      */
   974     boolean isSerializable() {
   975         return serializable;
   976     }
   978     /*
   979      * Get the externalizability of the class.
   980      */
   981     boolean isExternalizable() {
   982         return externalizable;
   983     }
   985     boolean isNonSerializable() {
   986         return ! (externalizable || serializable);
   987     }
   989     /*
   990      * Calculate the size of the array needed to store primitive data and the
   991      * number of object references to read when reading from the input
   992      * stream.
   993      */
   994     private void computeFieldInfo() {
   995         primBytes = 0;
   996         objFields = 0;
   998         for (int i = 0; i < fields.length; i++ ) {
   999             switch (fields[i].getTypeCode()) {
  1000             case 'B':
  1001             case 'Z':
  1002                 primBytes += 1;
  1003                 break;
  1004             case 'C':
  1005             case 'S':
  1006                 primBytes += 2;
  1007                 break;
  1009             case 'I':
  1010             case 'F':
  1011                 primBytes += 4;
  1012                 break;
  1013             case 'J':
  1014             case 'D' :
  1015                 primBytes += 8;
  1016                 break;
  1018             case 'L':
  1019             case '[':
  1020                 objFields += 1;
  1021                 break;
  1026     private static void msg( String str )
  1028         System.out.println( str ) ;
  1031     /* JDK 1.5 has introduced some new modifier bits (such as SYNTHETIC)
  1032      * that can affect the SVUID computation (see bug 4897937).  These bits
  1033      * must be ignored, as otherwise interoperability with ORBs in earlier
  1034      * JDK versions can be compromised.  I am adding these masks for this
  1035      * purpose as discussed in the CCC for this bug (see http://ccc.sfbay/4897937).
  1036      */
  1038     public static final int CLASS_MASK = Modifier.PUBLIC | Modifier.FINAL |
  1039         Modifier.INTERFACE | Modifier.ABSTRACT ;
  1040     public static final int FIELD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
  1041         Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
  1042         Modifier.TRANSIENT | Modifier.VOLATILE ;
  1043     public static final int METHOD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
  1044         Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
  1045         Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT |
  1046         Modifier.STRICT ;
  1048     /*
  1049      * Compute a hash for the specified class.  Incrementally add
  1050      * items to the hash accumulating in the digest stream.
  1051      * Fold the hash into a long.  Use the SHA secure hash function.
  1052      */
  1053     private static long _computeSerialVersionUID(Class<?> cl) {
  1054         if (DEBUG_SVUID)
  1055             msg( "Computing SerialVersionUID for " + cl ) ;
  1056         ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  1058         long h = 0;
  1059         try {
  1060             MessageDigest md = MessageDigest.getInstance("SHA");
  1061             DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  1062             DataOutputStream data = new DataOutputStream(mdo);
  1064             if (DEBUG_SVUID)
  1065                 msg( "\twriteUTF( \"" + cl.getName() + "\" )" ) ;
  1066             data.writeUTF(cl.getName());
  1068             int classaccess = cl.getModifiers();
  1069             classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
  1070                             Modifier.INTERFACE | Modifier.ABSTRACT);
  1072             /* Workaround for javac bug that only set ABSTRACT for
  1073              * interfaces if the interface had some methods.
  1074              * The ABSTRACT bit reflects that the number of methods > 0.
  1075              * This is required so correct hashes can be computed
  1076              * for existing class files.
  1077              * Previously this hack was previously present in the VM.
  1078              */
  1079             Method[] method = cl.getDeclaredMethods();
  1080             if ((classaccess & Modifier.INTERFACE) != 0) {
  1081                 classaccess &= (~Modifier.ABSTRACT);
  1082                 if (method.length > 0) {
  1083                     classaccess |= Modifier.ABSTRACT;
  1087             // Mask out any post-1.4 attributes
  1088             classaccess &= CLASS_MASK ;
  1090             if (DEBUG_SVUID)
  1091                 msg( "\twriteInt( " + classaccess + " ) " ) ;
  1092             data.writeInt(classaccess);
  1094             /*
  1095              * Get the list of interfaces supported,
  1096              * Accumulate their names their names in Lexical order
  1097              * and add them to the hash
  1098              */
  1099             if (!cl.isArray()) {
  1100                 /* In 1.2fcs, getInterfaces() was modified to return
  1101                  * {java.lang.Cloneable, java.io.Serializable} when
  1102                  * called on array classes.  These values would upset
  1103                  * the computation of the hash, so we explicitly omit
  1104                  * them from its computation.
  1105                  */
  1107                 Class<?> interfaces[] = cl.getInterfaces();
  1108                 Arrays.sort(interfaces, compareClassByName);
  1110                 for (int i = 0; i < interfaces.length; i++) {
  1111                     if (DEBUG_SVUID)
  1112                         msg( "\twriteUTF( \"" + interfaces[i].getName() + "\" ) " ) ;
  1113                     data.writeUTF(interfaces[i].getName());
  1117             /* Sort the field names to get a deterministic order */
  1118             Field[] field = cl.getDeclaredFields();
  1119             Arrays.sort(field, compareMemberByName);
  1121             for (int i = 0; i < field.length; i++) {
  1122                 Field f = field[i];
  1124                 /* Include in the hash all fields except those that are
  1125                  * private transient and private static.
  1126                  */
  1127                 int m = f.getModifiers();
  1128                 if (Modifier.isPrivate(m) &&
  1129                     (Modifier.isTransient(m) || Modifier.isStatic(m)))
  1130                     continue;
  1132                 if (DEBUG_SVUID)
  1133                     msg( "\twriteUTF( \"" + f.getName() + "\" ) " ) ;
  1134                 data.writeUTF(f.getName());
  1136                 // Mask out any post-1.4 bits
  1137                 m &= FIELD_MASK ;
  1139                 if (DEBUG_SVUID)
  1140                     msg( "\twriteInt( " + m + " ) " ) ;
  1141                 data.writeInt(m);
  1143                 if (DEBUG_SVUID)
  1144                     msg( "\twriteUTF( \"" + getSignature(f.getType()) + "\" ) " ) ;
  1145                 data.writeUTF(getSignature(f.getType()));
  1148             if (hasStaticInitializer(cl)) {
  1149                 if (DEBUG_SVUID)
  1150                     msg( "\twriteUTF( \"<clinit>\" ) " ) ;
  1151                 data.writeUTF("<clinit>");
  1153                 if (DEBUG_SVUID)
  1154                     msg( "\twriteInt( " + Modifier.STATIC + " )" ) ;
  1155                 data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
  1157                 if (DEBUG_SVUID)
  1158                     msg( "\twriteUTF( \"()V\" )" ) ;
  1159                 data.writeUTF("()V");
  1162             /*
  1163              * Get the list of constructors including name and signature
  1164              * Sort lexically, add all except the private constructors
  1165              * to the hash with their access flags
  1166              */
  1168             MethodSignature[] constructors =
  1169                 MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
  1170             for (int i = 0; i < constructors.length; i++) {
  1171                 MethodSignature c = constructors[i];
  1172                 String mname = "<init>";
  1173                 String desc = c.signature;
  1174                 desc = desc.replace('/', '.');
  1175                 if (DEBUG_SVUID)
  1176                     msg( "\twriteUTF( \"" + mname + "\" )" ) ;
  1177                 data.writeUTF(mname);
  1179                 // mask out post-1.4 modifiers
  1180                 int modifier = c.member.getModifiers() & METHOD_MASK ;
  1182                 if (DEBUG_SVUID)
  1183                     msg( "\twriteInt( " + modifier + " ) " ) ;
  1184                 data.writeInt( modifier ) ;
  1186                 if (DEBUG_SVUID)
  1187                     msg( "\twriteUTF( \"" + desc+ "\" )" ) ;
  1188                 data.writeUTF(desc);
  1191             /* Include in the hash all methods except those that are
  1192              * private transient and private static.
  1193              */
  1194             MethodSignature[] methods =
  1195                 MethodSignature.removePrivateAndSort(method);
  1196             for (int i = 0; i < methods.length; i++ ) {
  1197                 MethodSignature m = methods[i];
  1198                 String desc = m.signature;
  1199                 desc = desc.replace('/', '.');
  1201                 if (DEBUG_SVUID)
  1202                     msg( "\twriteUTF( \"" + m.member.getName()+ "\" )" ) ;
  1203                 data.writeUTF(m.member.getName());
  1205                 // mask out post-1.4 modifiers
  1206                 int modifier = m.member.getModifiers() & METHOD_MASK ;
  1208                 if (DEBUG_SVUID)
  1209                     msg( "\twriteInt( " + modifier + " ) " ) ;
  1210                 data.writeInt( modifier ) ;
  1212                 if (DEBUG_SVUID)
  1213                     msg( "\twriteUTF( \"" + desc + "\" )" ) ;
  1214                 data.writeUTF(desc);
  1217             /* Compute the hash value for this class.
  1218              * Use only the first 64 bits of the hash.
  1219              */
  1220             data.flush();
  1221             byte hasharray[] = md.digest();
  1222             for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  1223                 h += (long)(hasharray[i] & 255) << (i * 8);
  1225         } catch (IOException ignore) {
  1226             /* can't happen, but be deterministic anyway. */
  1227             h = -1;
  1228         } catch (NoSuchAlgorithmException complain) {
  1229             SecurityException se = new SecurityException() ;
  1230             se.initCause( complain ) ;
  1231             throw se ;
  1234         return h;
  1237     private static long computeStructuralUID(com.sun.corba.se.impl.io.ObjectStreamClass osc, Class<?> cl) {
  1238         ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  1240         long h = 0;
  1241         try {
  1243             if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
  1244                 (cl.isInterface())){
  1245                 return 0;
  1248             if (java.io.Externalizable.class.isAssignableFrom(cl)) {
  1249                 return 1;
  1252             MessageDigest md = MessageDigest.getInstance("SHA");
  1253             DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  1254             DataOutputStream data = new DataOutputStream(mdo);
  1256             // Get SUID of parent
  1257             Class<?> parent = cl.getSuperclass();
  1258             if ((parent != null))
  1259             // SerialBug 1; acc. to spec the one for
  1260             // java.lang.object
  1261             // should be computed and put
  1262             //     && (parent != java.lang.Object.class))
  1264                                 //data.writeLong(computeSerialVersionUID(null,parent));
  1265                 data.writeLong(computeStructuralUID(lookup(parent), parent));
  1268             if (osc.hasWriteObject())
  1269                 data.writeInt(2);
  1270             else
  1271                 data.writeInt(1);
  1273             // CORBA formal 00-11-03 10.6.2:  For each field of the
  1274             // class that is mapped to IDL, sorted lexicographically
  1275             // by Java field name, in increasing order...
  1276             ObjectStreamField[] field = osc.getFields();
  1277             if (field.length > 1) {
  1278                 Arrays.sort(field, compareObjStrFieldsByName);
  1281             // ...Java field name in UTF encoding, field
  1282             // descriptor, as defined by the JVM spec...
  1283             for (int i = 0; i < field.length; i++) {
  1284                 data.writeUTF(field[i].getName());
  1285                 data.writeUTF(field[i].getSignature());
  1288             /* Compute the hash value for this class.
  1289              * Use only the first 64 bits of the hash.
  1290              */
  1291             data.flush();
  1292             byte hasharray[] = md.digest();
  1293             // int minimum = Math.min(8, hasharray.length);
  1294             // SerialBug 3: SHA computation is wrong; for loop reversed
  1295             //for (int i = minimum; i > 0; i--)
  1296             for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  1297                 h += (long)(hasharray[i] & 255) << (i * 8);
  1299         } catch (IOException ignore) {
  1300             /* can't happen, but be deterministic anyway. */
  1301             h = -1;
  1302         } catch (NoSuchAlgorithmException complain) {
  1303             SecurityException se = new SecurityException();
  1304             se.initCause( complain ) ;
  1305             throw se ;
  1307         return h;
  1310     /**
  1311      * Compute the JVM signature for the class.
  1312      */
  1313     static String getSignature(Class<?> clazz) {
  1314         String type = null;
  1315         if (clazz.isArray()) {
  1316             Class<?> cl = clazz;
  1317             int dimensions = 0;
  1318             while (cl.isArray()) {
  1319                 dimensions++;
  1320                 cl = cl.getComponentType();
  1322             StringBuffer sb = new StringBuffer();
  1323             for (int i = 0; i < dimensions; i++) {
  1324                 sb.append("[");
  1326             sb.append(getSignature(cl));
  1327             type = sb.toString();
  1328         } else if (clazz.isPrimitive()) {
  1329             if (clazz == Integer.TYPE) {
  1330                 type = "I";
  1331             } else if (clazz == Byte.TYPE) {
  1332                 type = "B";
  1333             } else if (clazz == Long.TYPE) {
  1334                 type = "J";
  1335             } else if (clazz == Float.TYPE) {
  1336                 type = "F";
  1337             } else if (clazz == Double.TYPE) {
  1338                 type = "D";
  1339             } else if (clazz == Short.TYPE) {
  1340                 type = "S";
  1341             } else if (clazz == Character.TYPE) {
  1342                 type = "C";
  1343             } else if (clazz == Boolean.TYPE) {
  1344                 type = "Z";
  1345             } else if (clazz == Void.TYPE) {
  1346                 type = "V";
  1348         } else {
  1349             type = "L" + clazz.getName().replace('.', '/') + ";";
  1351         return type;
  1354     /*
  1355      * Compute the JVM method descriptor for the method.
  1356      */
  1357     static String getSignature(Method meth) {
  1358         StringBuffer sb = new StringBuffer();
  1360         sb.append("(");
  1362         Class<?>[] params = meth.getParameterTypes(); // avoid clone
  1363         for (int j = 0; j < params.length; j++) {
  1364             sb.append(getSignature(params[j]));
  1366         sb.append(")");
  1367         sb.append(getSignature(meth.getReturnType()));
  1368         return sb.toString();
  1371     /*
  1372      * Compute the JVM constructor descriptor for the constructor.
  1373      */
  1374     static String getSignature(Constructor cons) {
  1375         StringBuffer sb = new StringBuffer();
  1377         sb.append("(");
  1379         Class<?>[] params = cons.getParameterTypes(); // avoid clone
  1380         for (int j = 0; j < params.length; j++) {
  1381             sb.append(getSignature(params[j]));
  1383         sb.append(")V");
  1384         return sb.toString();
  1387     /*
  1388      * Cache of Class -> ClassDescriptor Mappings.
  1389      */
  1390     static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  1392     /*
  1393      * findDescriptorFor a Class.  This looks in the cache for a
  1394      * mapping from Class -> ObjectStreamClass mappings.  The hashCode
  1395      * of the Class is used for the lookup since the Class is the key.
  1396      * The entries are extended from java.lang.ref.SoftReference so the
  1397      * gc will be able to free them if needed.
  1398      */
  1399     private static ObjectStreamClass findDescriptorFor(Class<?> cl) {
  1401         int hash = cl.hashCode();
  1402         int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1403         ObjectStreamClassEntry e;
  1404         ObjectStreamClassEntry prev;
  1406         /* Free any initial entries whose refs have been cleared */
  1407         while ((e = descriptorFor[index]) != null && e.get() == null) {
  1408             descriptorFor[index] = e.next;
  1411         /* Traverse the chain looking for a descriptor with ofClass == cl.
  1412          * unlink entries that are unresolved.
  1413          */
  1414         prev = e;
  1415         while (e != null ) {
  1416             ObjectStreamClass desc = (ObjectStreamClass)(e.get());
  1417             if (desc == null) {
  1418                 // This entry has been cleared,  unlink it
  1419                 prev.next = e.next;
  1420             } else {
  1421                 if (desc.ofClass == cl)
  1422                     return desc;
  1423                 prev = e;
  1425             e = e.next;
  1427         return null;
  1430     /*
  1431      * insertDescriptorFor a Class -> ObjectStreamClass mapping.
  1432      */
  1433     private static void insertDescriptorFor(ObjectStreamClass desc) {
  1434         // Make sure not already present
  1435         if (findDescriptorFor(desc.ofClass) != null) {
  1436             return;
  1439         int hash = desc.ofClass.hashCode();
  1440         int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1441         ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
  1442         e.next = descriptorFor[index];
  1443         descriptorFor[index] = e;
  1446     private static Field[] getDeclaredFields(final Class<?> clz) {
  1447         return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
  1448             public Object run() {
  1449                 return clz.getDeclaredFields();
  1451         });
  1455     /*
  1456      * The name of this descriptor
  1457      */
  1458     private String name;
  1460     /*
  1461      * The descriptor of the supertype.
  1462      */
  1463     private ObjectStreamClass superclass;
  1465     /*
  1466      * Flags for Serializable and Externalizable.
  1467      */
  1468     private boolean serializable;
  1469     private boolean externalizable;
  1471     /*
  1472      * Array of persistent fields of this class, sorted by
  1473      * type and name.
  1474      */
  1475     private ObjectStreamField[] fields;
  1477     /*
  1478      * Class that is a descriptor for in this virtual machine.
  1479      */
  1480     private Class<?> ofClass;
  1482     /*
  1483      * True if descriptor for a proxy class.
  1484      */
  1485     boolean forProxyClass;
  1488     /*
  1489      * SerialVersionUID for this class.
  1490      */
  1491     private long suid = kDefaultUID;
  1492     private String suidStr = null;
  1494     /*
  1495      * Actual (computed) SerialVersionUID for this class.
  1496      */
  1497     private long actualSuid = kDefaultUID;
  1498     private String actualSuidStr = null;
  1500     /*
  1501      * The total number of bytes of primitive fields.
  1502      * The total number of object fields.
  1503      */
  1504     int primBytes;
  1505     int objFields;
  1507     /**
  1508      * Flag indicating whether or not this instance has
  1509      * successfully completed initialization.  This is to
  1510      * try to fix bug 4373844.  Working to move to
  1511      * reusing java.io.ObjectStreamClass for JDK 1.5.
  1512      */
  1513     private boolean initialized = false;
  1515     /* Internal lock object. */
  1516     private Object lock = new Object();
  1518     /* In JDK 1.1, external data was not written in block mode.
  1519      * As of JDK 1.2, external data is written in block data mode. This
  1520      * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
  1522      * @since JDK 1.2
  1523      */
  1524     private boolean hasExternalizableBlockData;
  1525     Method writeObjectMethod;
  1526     Method readObjectMethod;
  1527     private transient Method writeReplaceObjectMethod;
  1528     private transient Method readResolveObjectMethod;
  1529     private Constructor cons ;
  1531     /**
  1532      * Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a
  1533      * stream format version 2 which puts a fake valuetype around
  1534      * a Serializable's optional custom data.  This valuetype has
  1535      * a special repository ID made from the Serializable's
  1536      * information which we are pre-computing and
  1537      * storing here.
  1538      */
  1539     private String rmiiiopOptionalDataRepId = null;
  1541     /*
  1542      * ObjectStreamClass that this one was built from.
  1543      */
  1544     private ObjectStreamClass localClassDesc;
  1546     /* Find out if the class has a static class initializer <clinit> */
  1547     private static Method hasStaticInitializerMethod = null;
  1548     /**
  1549      * Returns true if the given class defines a static initializer method,
  1550      * false otherwise.
  1551      */
  1552     private static boolean hasStaticInitializer(Class<?> cl) {
  1553         if (hasStaticInitializerMethod == null) {
  1554             Class<?> classWithThisMethod = null;
  1556             try {
  1557                 if (classWithThisMethod == null)
  1558                     classWithThisMethod = java.io.ObjectStreamClass.class;
  1560                 hasStaticInitializerMethod =
  1561                     classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
  1562                                                           new Class<?>[] { Class.class });
  1563             } catch (NoSuchMethodException ex) {
  1566             if (hasStaticInitializerMethod == null) {
  1567                 // XXX I18N, logging needed
  1568                 throw new InternalError("Can't find hasStaticInitializer method on "
  1569                                         + classWithThisMethod.getName());
  1571             hasStaticInitializerMethod.setAccessible(true);
  1574         try {
  1575             Boolean retval = (Boolean)
  1576                 hasStaticInitializerMethod.invoke(null, new Object[] { cl });
  1577             return retval.booleanValue();
  1578         } catch (Exception ex) {
  1579             // XXX I18N, logging needed
  1580             InternalError ie = new InternalError( "Error invoking hasStaticInitializer" ) ;
  1581             ie.initCause( ex ) ;
  1582             throw ie ;
  1587     /** use serialVersionUID from JDK 1.1. for interoperability */
  1588     private static final long serialVersionUID = -6120832682080437368L;
  1590     /**
  1591      * Set serialPersistentFields of a Serializable class to this value to
  1592      * denote that the class has no Serializable fields.
  1593      */
  1594     public static final ObjectStreamField[] NO_FIELDS =
  1595         new ObjectStreamField[0];
  1597     /*
  1598      * Entries held in the Cache of known ObjectStreamClass objects.
  1599      * Entries are chained together with the same hash value (modulo array size).
  1600      */
  1601     private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
  1603         ObjectStreamClassEntry(ObjectStreamClass c) {
  1604             //super(c);
  1605             this.c = c;
  1607         ObjectStreamClassEntry next;
  1609         public Object get()
  1611             return c;
  1613         private ObjectStreamClass c;
  1616     /*
  1617      * Comparator object for Classes and Interfaces
  1618      */
  1619     private static Comparator compareClassByName =
  1620         new CompareClassByName();
  1622     private static class CompareClassByName implements Comparator {
  1623         public int compare(Object o1, Object o2) {
  1624             Class<?> c1 = (Class)o1;
  1625             Class<?> c2 = (Class)o2;
  1626             return (c1.getName()).compareTo(c2.getName());
  1630     /**
  1631      * Comparator for ObjectStreamFields by name
  1632      */
  1633     private final static Comparator compareObjStrFieldsByName
  1634         = new CompareObjStrFieldsByName();
  1636     private static class CompareObjStrFieldsByName implements Comparator {
  1637         public int compare(Object o1, Object o2) {
  1638             ObjectStreamField osf1 = (ObjectStreamField)o1;
  1639             ObjectStreamField osf2 = (ObjectStreamField)o2;
  1641             return osf1.getName().compareTo(osf2.getName());
  1645     /*
  1646      * Comparator object for Members, Fields, and Methods
  1647      */
  1648     private static Comparator compareMemberByName =
  1649         new CompareMemberByName();
  1651     private static class CompareMemberByName implements Comparator {
  1652         public int compare(Object o1, Object o2) {
  1653             String s1 = ((Member)o1).getName();
  1654             String s2 = ((Member)o2).getName();
  1656             if (o1 instanceof Method) {
  1657                 s1 += getSignature((Method)o1);
  1658                 s2 += getSignature((Method)o2);
  1659             } else if (o1 instanceof Constructor) {
  1660                 s1 += getSignature((Constructor)o1);
  1661                 s2 += getSignature((Constructor)o2);
  1663             return s1.compareTo(s2);
  1667     /* It is expensive to recompute a method or constructor signature
  1668        many times, so compute it only once using this data structure. */
  1669     private static class MethodSignature implements Comparator {
  1670         Member member;
  1671         String signature;      // cached parameter signature
  1673         /* Given an array of Method or Constructor members,
  1674            return a sorted array of the non-private members.*/
  1675         /* A better implementation would be to implement the returned data
  1676            structure as an insertion sorted link list.*/
  1677         static MethodSignature[] removePrivateAndSort(Member[] m) {
  1678             int numNonPrivate = 0;
  1679             for (int i = 0; i < m.length; i++) {
  1680                 if (! Modifier.isPrivate(m[i].getModifiers())) {
  1681                     numNonPrivate++;
  1684             MethodSignature[] cm = new MethodSignature[numNonPrivate];
  1685             int cmi = 0;
  1686             for (int i = 0; i < m.length; i++) {
  1687                 if (! Modifier.isPrivate(m[i].getModifiers())) {
  1688                     cm[cmi] = new MethodSignature(m[i]);
  1689                     cmi++;
  1692             if (cmi > 0)
  1693                 Arrays.sort(cm, cm[0]);
  1694             return cm;
  1697         /* Assumes that o1 and o2 are either both methods
  1698            or both constructors.*/
  1699         public int compare(Object o1, Object o2) {
  1700             /* Arrays.sort calls compare when o1 and o2 are equal.*/
  1701             if (o1 == o2)
  1702                 return 0;
  1704             MethodSignature c1 = (MethodSignature)o1;
  1705             MethodSignature c2 = (MethodSignature)o2;
  1707             int result;
  1708             if (isConstructor()) {
  1709                 result = c1.signature.compareTo(c2.signature);
  1710             } else { // is a Method.
  1711                 result = c1.member.getName().compareTo(c2.member.getName());
  1712                 if (result == 0)
  1713                     result = c1.signature.compareTo(c2.signature);
  1715             return result;
  1718         final private boolean isConstructor() {
  1719             return member instanceof Constructor;
  1721         private MethodSignature(Member m) {
  1722             member = m;
  1723             if (isConstructor()) {
  1724                 signature = ObjectStreamClass.getSignature((Constructor)m);
  1725             } else {
  1726                 signature = ObjectStreamClass.getSignature((Method)m);
  1731     /**
  1732      * Returns non-static, non-abstract method with given signature provided it
  1733      * is defined by or accessible (via inheritance) by the given class, or
  1734      * null if no match found.  Access checks are disabled on the returned
  1735      * method (if any).
  1737      * Copied from the Merlin java.io.ObjectStreamClass.
  1738      */
  1739     private static Method getInheritableMethod(Class<?> cl, String name,
  1740                                                Class<?>[] argTypes,
  1741                                                Class<?> returnType)
  1743         Method meth = null;
  1744         Class<?> defCl = cl;
  1745         while (defCl != null) {
  1746             try {
  1747                 meth = defCl.getDeclaredMethod(name, argTypes);
  1748                 break;
  1749             } catch (NoSuchMethodException ex) {
  1750                 defCl = defCl.getSuperclass();
  1754         if ((meth == null) || (meth.getReturnType() != returnType)) {
  1755             return null;
  1757         meth.setAccessible(true);
  1758         int mods = meth.getModifiers();
  1759         if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
  1760             return null;
  1761         } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
  1762             return meth;
  1763         } else if ((mods & Modifier.PRIVATE) != 0) {
  1764             return (cl == defCl) ? meth : null;
  1765         } else {
  1766             return packageEquals(cl, defCl) ? meth : null;
  1770     /**
  1771      * Returns true if classes are defined in the same package, false
  1772      * otherwise.
  1774      * Copied from the Merlin java.io.ObjectStreamClass.
  1775      */
  1776     private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
  1777         Package pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage();
  1778         return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2))));

mercurial