src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java

Wed, 27 Apr 2016 01:21:28 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:21:28 +0800
changeset 0
7ef37b2cdcad
child 748
6845b95cba6b
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/corba/
changeset: 765:f46df0af2ca8
tag: jdk8u25-b17

     1 /*
     2  * Copyright (c) 2001, 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 1999  All Rights Reserved
    29  *
    30  */
    32 package com.sun.corba.se.impl.orbutil;
    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.Serializable;
    56 import java.io.Externalizable;
    58 import java.util.Arrays;
    59 import java.util.Comparator;
    60 import java.util.Hashtable;
    62 import org.omg.CORBA.ValueMember;
    64 import com.sun.corba.se.impl.io.ValueUtility;
    65 import com.sun.corba.se.impl.io.ObjectStreamClass;
    67 /**
    68  * This is duplicated here to preserve the JDK 1.3.1FCS behavior
    69  * of calculating the OMG hash code incorrectly when serialPersistentFields
    70  * is used, but some of the fields no longer exist in the class itself.
    71  *
    72  * We have to duplicate it since we aren't allowed to modify the
    73  * com.sun.corba.se.impl.io version further, and can't make it
    74  * public outside of its package for security reasons.
    75  */
    76 /**
    77  * A ObjectStreamClass_1_3_1 describes a class that can be serialized to a stream
    78  * or a class that was serialized to a stream.  It contains the name
    79  * and the serialVersionUID of the class.
    80  * <br>
    81  * The ObjectStreamClass_1_3_1 for a specific class loaded in this Java VM can
    82  * be found using the lookup method.
    83  *
    84  * @author  Roger Riggs
    85  * @since   JDK1.1
    86  */
    87 public class ObjectStreamClass_1_3_1 implements java.io.Serializable {
    89     public static final long kDefaultUID = -1;
    91     private static Object noArgsList[] = {};
    92     private static Class<?> noTypesList[] = {};
    94     private static Hashtable translatedFields;
    96     /** Find the descriptor for a class that can be serialized.  Null
    97      * is returned if the specified class does not implement
    98      * java.io.Serializable or java.io.Externalizable.
    99      */
   100     static final ObjectStreamClass_1_3_1 lookup(Class<?> cl)
   101     {
   102         ObjectStreamClass_1_3_1 desc = lookupInternal(cl);
   103         if (desc.isSerializable() || desc.isExternalizable())
   104             return desc;
   105         return null;
   106     }
   108     /*
   109      * Find the class descriptor for the specified class.
   110      * Package access only so it can be called from ObjectIn/OutStream.
   111      */
   112     static ObjectStreamClass_1_3_1 lookupInternal(Class<?> cl)
   113     {
   114         /* Synchronize on the hashtable so no two threads will do
   115          * this at the same time.
   116          */
   117         ObjectStreamClass_1_3_1 desc = null;
   118         synchronized (descriptorFor) {
   119             /* Find the matching descriptor if it already known */
   120             desc = findDescriptorFor(cl);
   121             if (desc != null) {
   122                 return desc;
   123             }
   125                 /* Check if it's serializable */
   126                 boolean serializable = Serializable.class.isAssignableFrom(cl);
   127                 /* If the class is only Serializable,
   128                  * lookup the descriptor for the superclass.
   129                  */
   130                 ObjectStreamClass_1_3_1 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_1_3_1(cl, superdesc,
   155                                          serializable, externalizable);
   156         }
   157         desc.init();
   158         return desc;
   159     }
   161     /**
   162      * The name of the class described by this descriptor.
   163      */
   164     public final String getName() {
   165         return name;
   166     }
   168     /**
   169      * Return the serialVersionUID for this class.
   170      * The serialVersionUID defines a set of classes all with the same name
   171      * that have evolved from a common root class and agree to be serialized
   172      * and deserialized using a common format.
   173      */
   174     public static final long getSerialVersionUID( java.lang.Class<?> clazz) {
   175         ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
   176         if( theosc != null )
   177         {
   178                 return theosc.getSerialVersionUID( );
   179         }
   180         return 0;
   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 final long getSerialVersionUID() {
   190         return suid;
   191     }
   193     /**
   194      * Return the serialVersionUID string for this class.
   195      * The serialVersionUID defines a set of classes all with the same name
   196      * that have evolved from a common root class and agree to be serialized
   197      * and deserialized using a common format.
   198      */
   199     public final String getSerialVersionUIDStr() {
   200         if (suidStr == null)
   201             suidStr = Long.toHexString(suid).toUpperCase();
   202         return suidStr;
   203     }
   205     /**
   206      * Return the actual (computed) serialVersionUID for this class.
   207      */
   208     public static final long getActualSerialVersionUID( java.lang.Class<?> clazz )
   209     {
   210         ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
   211         if( theosc != null )
   212         {
   213                 return theosc.getActualSerialVersionUID( );
   214         }
   215         return 0;
   216     }
   218     /**
   219      * Return the actual (computed) serialVersionUID for this class.
   220      */
   221     public final long getActualSerialVersionUID() {
   222         return actualSuid;
   223     }
   225     /**
   226      * Return the actual (computed) serialVersionUID for this class.
   227      */
   228     public final String getActualSerialVersionUIDStr() {
   229         if (actualSuidStr == null)
   230             actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
   231         return actualSuidStr;
   232     }
   234     /**
   235      * Return the class in the local VM that this version is mapped to.
   236      * Null is returned if there is no corresponding local class.
   237      */
   238     public final Class<?> forClass() {
   239         return ofClass;
   240     }
   242     /**
   243      * Return an array of the fields of this serializable class.
   244      * @return an array containing an element for each persistent
   245      * field of this class. Returns an array of length zero if
   246      * there are no fields.
   247      * @since JDK1.2
   248      */
   249     public ObjectStreamField[] getFields() {
   250         // Return a copy so the caller can't change the fields.
   251         if (fields.length > 0) {
   252             ObjectStreamField[] dup = new ObjectStreamField[fields.length];
   253             System.arraycopy(fields, 0, dup, 0, fields.length);
   254             return dup;
   255         } else {
   256             return fields;
   257         }
   258     }
   260     public boolean hasField(ValueMember field){
   262         for (int i = 0; i < fields.length; i++){
   263             try{
   264                 if (fields[i].getName().equals(field.name)) {
   266                     if (fields[i].getSignature().equals(ValueUtility.getSignature(field)))
   267                         return true;
   268                 }
   269             }
   270             catch(Throwable t){}
   271         }
   272         return false;
   273     }
   275     /* Avoid unnecessary allocations. */
   276     final ObjectStreamField[] getFieldsNoCopy() {
   277         return fields;
   278     }
   280     /**
   281      * Get the field of this class by name.
   282      * @return The ObjectStreamField object of the named field or null if there
   283      * is no such named field.
   284      */
   285     public final ObjectStreamField getField(String name) {
   286         /* Binary search of fields by name.
   287          */
   288         for (int i = fields.length-1; i >= 0; i--) {
   289             if (name.equals(fields[i].getName())) {
   290                 return fields[i];
   291             }
   292         }
   293         return null;
   294     }
   296     public Serializable writeReplace(Serializable value) {
   297         if (writeReplaceObjectMethod != null) {
   298             try {
   299                 return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
   300             }
   301             catch(Throwable t) {
   302                 throw new RuntimeException(t.getMessage());
   303             }
   304         }
   305         else return value;
   306     }
   308     public Object readResolve(Object value) {
   309         if (readResolveObjectMethod != null) {
   310             try {
   311                 return readResolveObjectMethod.invoke(value,noArgsList);
   312             }
   313             catch(Throwable t) {
   314                 throw new RuntimeException(t.getMessage());
   315             }
   316         }
   317         else return value;
   318     }
   320     /**
   321      * Return a string describing this ObjectStreamClass_1_3_1.
   322      */
   323     public final String toString() {
   324         StringBuffer sb = new StringBuffer();
   326         sb.append(name);
   327         sb.append(": static final long serialVersionUID = ");
   328         sb.append(Long.toString(suid));
   329         sb.append("L;");
   330         return sb.toString();
   331     }
   333     /*
   334      * Create a new ObjectStreamClass_1_3_1 from a loaded class.
   335      * Don't call this directly, call lookup instead.
   336      */
   337     private ObjectStreamClass_1_3_1(java.lang.Class<?> cl, ObjectStreamClass_1_3_1 superdesc,
   338                               boolean serial, boolean extern)
   339     {
   340         ofClass = cl;           /* created from this class */
   342         if (Proxy.isProxyClass(cl)) {
   343             forProxyClass = true;
   344         }
   346         name = cl.getName();
   347         superclass = superdesc;
   348         serializable = serial;
   349         if (!forProxyClass) {
   350             // proxy classes are never externalizable
   351             externalizable = extern;
   352         }
   354         /*
   355          * Enter this class in the table of known descriptors.
   356          * Otherwise, when the fields are read it may recurse
   357          * trying to find the descriptor for itself.
   358          */
   359         insertDescriptorFor(this);
   361         /*
   362          * The remainder of initialization occurs in init(), which is called
   363          * after the lock on the global class descriptor table has been
   364          * released.
   365          */
   366     }
   368     /*
   369      * Initialize class descriptor.  This method is only invoked on class
   370      * descriptors created via calls to lookupInternal().  This method is kept
   371      * separate from the ObjectStreamClass_1_3_1 constructor so that lookupInternal
   372      * does not have to hold onto a global class descriptor table lock while the
   373      * class descriptor is being initialized (see bug 4165204).
   374      */
   377     private void init() {
   378       synchronized (lock) {
   380         final Class<?> cl = ofClass;
   382         if (fields != null) // already initialized
   383                 return;
   386         if (!serializable ||
   387             externalizable ||
   388             forProxyClass ||
   389             name.equals("java.lang.String")) {
   390             fields = NO_FIELDS;
   391         } else if (serializable) {
   393             /* Ask for permission to override field access checks.
   394              */
   395             AccessController.doPrivileged(new PrivilegedAction() {
   396                 public Object run() {
   397                 /* Fill in the list of persistent fields.
   398                  * If it is declared, use the declared serialPersistentFields.
   399                  * Otherwise, extract the fields from the class itself.
   400                  */
   401                 try {
   402                     Field pf = cl.getDeclaredField("serialPersistentFields");
   403                     // serial bug 7; the serialPersistentFields were not
   404                     // being read and stored as Accessible bit was not set
   405                     pf.setAccessible(true);
   406                     // serial bug 7; need to find if the field is of type
   407                     // java.io.ObjectStreamField
   408                     java.io.ObjectStreamField[] f =
   409                            (java.io.ObjectStreamField[])pf.get(cl);
   410                     int mods = pf.getModifiers();
   411                     if ((Modifier.isPrivate(mods)) &&
   412                         (Modifier.isStatic(mods)) &&
   413                         (Modifier.isFinal(mods)))
   414                     {
   415                         fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl));
   416                     }
   417                 } catch (NoSuchFieldException e) {
   418                     fields = null;
   419                 } catch (IllegalAccessException e) {
   420                     fields = null;
   421                 } catch (IllegalArgumentException e) {
   422                     fields = null;
   423                 } catch (ClassCastException e) {
   424                     /* Thrown if a field serialPersistentField exists
   425                      * but it is not of type ObjectStreamField.
   426                      */
   427                     fields = null;
   428                 }
   431                 if (fields == null) {
   432                     /* Get all of the declared fields for this
   433                      * Class. setAccessible on all fields so they
   434                      * can be accessed later.  Create a temporary
   435                      * ObjectStreamField array to hold each
   436                      * non-static, non-transient field. Then copy the
   437                      * temporary array into an array of the correct
   438                      * size once the number of fields is known.
   439                      */
   440                     Field[] actualfields = cl.getDeclaredFields();
   442                     int numFields = 0;
   443                     ObjectStreamField[] tempFields =
   444                         new ObjectStreamField[actualfields.length];
   445                     for (int i = 0; i < actualfields.length; i++) {
   446                         int modifiers = actualfields[i].getModifiers();
   447                         if (!Modifier.isStatic(modifiers) &&
   448                             !Modifier.isTransient(modifiers)) {
   449                             tempFields[numFields++] =
   450                                 new ObjectStreamField(actualfields[i]);
   451                         }
   452                     }
   453                     fields = new ObjectStreamField[numFields];
   454                     System.arraycopy(tempFields, 0, fields, 0, numFields);
   456                 } else {
   457                     // For each declared persistent field, look for an actual
   458                     // reflected Field. If there is one, make sure it's the correct
   459                     // type and cache it in the ObjectStreamClass_1_3_1 for that field.
   460                     for (int j = fields.length-1; j >= 0; j--) {
   461                         try {
   462                             Field reflField = cl.getDeclaredField(fields[j].getName());
   463                             if (fields[j].getType() == reflField.getType()) {
   464                                 // reflField.setAccessible(true);
   465                                 fields[j].setField(reflField);
   466                             }
   467                         } catch (NoSuchFieldException e) {
   468                             // Nothing to do
   469                         }
   470                     }
   471                 }
   472                 return null;
   473             }
   474             });
   476             if (fields.length > 1)
   477                 Arrays.sort(fields);
   479             /* Set up field data for use while writing using the API api. */
   480             computeFieldInfo();
   481         }
   483         /* Get the serialVersionUID from the class.
   484          * It uses the access override mechanism so make sure
   485          * the field objects is only used here.
   486          *
   487          * NonSerializable classes have a serialVerisonUID of 0L.
   488          */
   489          if (isNonSerializable()) {
   490              suid = 0L;
   491          } else {
   492              // Lookup special Serializable members using reflection.
   493              AccessController.doPrivileged(new PrivilegedAction() {
   494                 public Object run() {
   495                 if (forProxyClass) {
   496                     // proxy classes always have serialVersionUID of 0L
   497                     suid = 0L;
   498                 } else {
   499                     try {
   500                         final Field f = cl.getDeclaredField("serialVersionUID");
   501                         int mods = f.getModifiers();
   502                     // SerialBug 5:  static final SUID should be read
   503                         if (Modifier.isStatic(mods) &&
   504                             Modifier.isFinal(mods) ) {
   505                             f.setAccessible(true);
   506                             suid = f.getLong(cl);
   507                             // get rid of native code
   508                             // suid = getSerialVersionUIDField(cl);
   509                     // SerialBug 2: should be computed after writeObject
   510                     // actualSuid = computeStructuralUID(cl);
   511                         } else {
   512                             suid = ObjectStreamClass.getSerialVersionUID(cl);
   513                             // SerialBug 2: should be computed after writeObject
   514                             // actualSuid = computeStructuralUID(cl);
   515                         }
   516                     } catch (NoSuchFieldException ex) {
   517                         suid = ObjectStreamClass.getSerialVersionUID(cl);
   518                         // SerialBug 2: should be computed after writeObject
   519                         // actualSuid = computeStructuralUID(cl);
   520                     } catch (IllegalAccessException ex) {
   521                         suid = ObjectStreamClass.getSerialVersionUID(cl);
   522                     }
   523                 }
   526                 try {
   527                     writeReplaceObjectMethod = cl.getDeclaredMethod("writeReplace", noTypesList);
   528                     if (Modifier.isStatic(writeReplaceObjectMethod.getModifiers())) {
   529                         writeReplaceObjectMethod = null;
   530                     } else {
   531                         writeReplaceObjectMethod.setAccessible(true);
   532                     }
   534                 } catch (NoSuchMethodException e2) {
   536                 }
   538                 try {
   539                     readResolveObjectMethod = cl.getDeclaredMethod("readResolve", noTypesList);
   540                     if (Modifier.isStatic(readResolveObjectMethod.getModifiers())) {
   541                        readResolveObjectMethod = null;
   542                     } else {
   543                        readResolveObjectMethod.setAccessible(true);
   544                     }
   546                 } catch (NoSuchMethodException e2) {
   548                 }
   550                 /* Cache lookup of writeObject and readObject for
   551                  * Serializable classes. (Do not lookup for
   552                  * Externalizable)
   553                  */
   555                 if (serializable && !forProxyClass) {
   557                     /* Look for the writeObject method
   558                      * Set the accessible flag on it here. ObjectOutputStream
   559                      * will call it as necessary.
   560                      */
   561                     try {
   562                       Class<?>[] args = {java.io.ObjectOutputStream.class};
   563                       writeObjectMethod = cl.getDeclaredMethod("writeObject", args);
   564                       hasWriteObjectMethod = true;
   565                       int mods = writeObjectMethod.getModifiers();
   567                       // Method must be private and non-static
   568                       if (!Modifier.isPrivate(mods) ||
   569                         Modifier.isStatic(mods)) {
   570                         writeObjectMethod = null;
   571                         hasWriteObjectMethod = false;
   572                       }
   574                     } catch (NoSuchMethodException e) {
   575                     }
   577                     /* Look for the readObject method
   578                      * set the access override and save the reference for
   579                      * ObjectInputStream so it can all the method directly.
   580                      */
   581                     try {
   582                       Class<?>[] args = {java.io.ObjectInputStream.class};
   583                       readObjectMethod = cl.getDeclaredMethod("readObject", args);
   584                       int mods = readObjectMethod.getModifiers();
   586                       // Method must be private and non-static
   587                       if (!Modifier.isPrivate(mods) ||
   588                         Modifier.isStatic(mods)) {
   589                         readObjectMethod = null;
   590                       }
   591                     } catch (NoSuchMethodException e) {
   592                     }
   593                     // Compute the structural UID.  This must be done after the
   594                     // calculation for writeObject.  Fixed 4/20/2000, eea1
   595                     // SerialBug 2: to have correct value in RepId
   596                 }
   597                 return null;
   598             }
   599           });
   600         }
   602         actualSuid = computeStructuralUID(this, cl);
   603       }
   605     }
   607     /*
   608      * Create an empty ObjectStreamClass_1_3_1 for a class about to be read.
   609      * This is separate from read so ObjectInputStream can assign the
   610      * wire handle early, before any nested ObjectStreamClass_1_3_1 might
   611      * be read.
   612      */
   613     ObjectStreamClass_1_3_1(String n, long s) {
   614         name = n;
   615         suid = s;
   616         superclass = null;
   617     }
   619     private static Object[] translateFields(Object objs[])
   620         throws NoSuchFieldException {
   621         try{
   622             java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs;
   623             Object translation[] = null;
   625             if (translatedFields == null)
   626                 translatedFields = new Hashtable();
   628             translation = (Object[])translatedFields.get(fields);
   630             if (translation != null)
   631                 return translation;
   632             else {
   633                 Class<?> osfClass = com.sun.corba.se.impl.orbutil.ObjectStreamField.class;
   635                 translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
   636                 Object arg[] = new Object[2];
   637                 Class<?> types[] = {String.class, Class.class};
   638                 Constructor constructor = osfClass.getDeclaredConstructor(types);
   639                 for (int i = fields.length -1; i >= 0; i--){
   640                     arg[0] = fields[i].getName();
   641                     arg[1] = fields[i].getType();
   643                     translation[i] = constructor.newInstance(arg);
   644                 }
   645                 translatedFields.put(fields, translation);
   647             }
   649             return (Object[])translation;
   650         }
   651         catch(Throwable t){
   652             throw new NoSuchFieldException();
   653         }
   654     }
   656     /* Compare the base class names of streamName and localName.
   657      *
   658      * @return  Return true iff the base class name compare.
   659      * @parameter streamName    Fully qualified class name.
   660      * @parameter localName     Fully qualified class name.
   661      * @parameter pkgSeparator  class names use either '.' or '/'.
   662      *
   663      * Only compare base class name to allow package renaming.
   664      */
   665     static boolean compareClassNames(String streamName,
   666                                      String localName,
   667                                      char pkgSeparator) {
   668         /* compare the class names, stripping off package names. */
   669         int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
   670         if (streamNameIndex < 0)
   671             streamNameIndex = 0;
   673         int localNameIndex = localName.lastIndexOf(pkgSeparator);
   674         if (localNameIndex < 0)
   675             localNameIndex = 0;
   677         return streamName.regionMatches(false, streamNameIndex,
   678                                         localName, localNameIndex,
   679                                         streamName.length() - streamNameIndex);
   680     }
   682     /*
   683      * Compare the types of two class descriptors.
   684      * They match if they have the same class name and suid
   685      */
   686     final boolean typeEquals(ObjectStreamClass_1_3_1 other) {
   687         return (suid == other.suid) &&
   688             compareClassNames(name, other.name, '.');
   689     }
   691     /*
   692      * Return the superclass descriptor of this descriptor.
   693      */
   694     final void setSuperclass(ObjectStreamClass_1_3_1 s) {
   695         superclass = s;
   696     }
   698     /*
   699      * Return the superclass descriptor of this descriptor.
   700      */
   701     final ObjectStreamClass_1_3_1 getSuperclass() {
   702         return superclass;
   703     }
   705     /*
   706      * Return whether the class has a writeObject method
   707      */
   708     final boolean hasWriteObject() {
   709         return hasWriteObjectMethod;
   710     }
   712     final boolean isCustomMarshaled() {
   713         return (hasWriteObject() || isExternalizable());
   714     }
   716     /*
   717      * Return true if all instances of 'this' Externalizable class
   718      * are written in block-data mode from the stream that 'this' was read
   719      * from. <p>
   720      *
   721      * In JDK 1.1, all Externalizable instances are not written
   722      * in block-data mode.
   723      * In JDK 1.2, all Externalizable instances, by default, are written
   724      * in block-data mode and the Externalizable instance is terminated with
   725      * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
   726      * instances.
   727      *
   728      * IMPLEMENTATION NOTE:
   729      *   This should have been a mode maintained per stream; however,
   730      *   for compatibility reasons, it was only possible to record
   731      *   this change per class. All Externalizable classes within
   732      *   a given stream should either have this mode enabled or
   733      *   disabled. This is enforced by not allowing the PROTOCOL_VERSION
   734      *   of a stream to he changed after any objects have been written.
   735      *
   736      * @see ObjectOutputStream#useProtocolVersion
   737      * @see ObjectStreamConstants#PROTOCOL_VERSION_1
   738      * @see ObjectStreamConstants#PROTOCOL_VERSION_2
   739      *
   740      * @since JDK 1.2
   741      */
   742     boolean hasExternalizableBlockDataMode() {
   743         return hasExternalizableBlockData;
   744     }
   746     /*
   747      * Return the ObjectStreamClass_1_3_1 of the local class this one is based on.
   748      */
   749     final ObjectStreamClass_1_3_1 localClassDescriptor() {
   750         return localClassDesc;
   751     }
   753     /*
   754      * Get the Serializability of the class.
   755      */
   756     boolean isSerializable() {
   757         return serializable;
   758     }
   760     /*
   761      * Get the externalizability of the class.
   762      */
   763     boolean isExternalizable() {
   764         return externalizable;
   765     }
   767     boolean isNonSerializable() {
   768         return ! (externalizable || serializable);
   769     }
   771     /*
   772      * Calculate the size of the array needed to store primitive data and the
   773      * number of object references to read when reading from the input
   774      * stream.
   775      */
   776     private void computeFieldInfo() {
   777         primBytes = 0;
   778         objFields = 0;
   780         for (int i = 0; i < fields.length; i++ ) {
   781             switch (fields[i].getTypeCode()) {
   782             case 'B':
   783             case 'Z':
   784                 primBytes += 1;
   785                 break;
   786             case 'C':
   787             case 'S':
   788                 primBytes += 2;
   789                 break;
   791             case 'I':
   792             case 'F':
   793                 primBytes += 4;
   794                 break;
   795             case 'J':
   796             case 'D' :
   797                 primBytes += 8;
   798                 break;
   800             case 'L':
   801             case '[':
   802                 objFields += 1;
   803                 break;
   804             }
   805         }
   806     }
   808     private static long computeStructuralUID(ObjectStreamClass_1_3_1 osc, Class<?> cl) {
   809         ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
   811         long h = 0;
   812         try {
   814             if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
   815                 (cl.isInterface())){
   816                 return 0;
   817             }
   819             if (java.io.Externalizable.class.isAssignableFrom(cl)) {
   820                 return 1;
   821             }
   823             MessageDigest md = MessageDigest.getInstance("SHA");
   824             DigestOutputStream mdo = new DigestOutputStream(devnull, md);
   825             DataOutputStream data = new DataOutputStream(mdo);
   827             // Get SUID of parent
   828             Class<?> parent = cl.getSuperclass();
   829             if ((parent != null))
   830             // SerialBug 1; acc. to spec the one for
   831             // java.lang.object
   832             // should be computed and put
   833             //     && (parent != java.lang.Object.class))
   834             {
   835                                 //data.writeLong(computeSerialVersionUID(null,parent));
   836                 data.writeLong(computeStructuralUID(lookup(parent), parent));
   837             }
   839             if (osc.hasWriteObject())
   840                 data.writeInt(2);
   841             else
   842                 data.writeInt(1);
   844             /* Sort the field names to get a deterministic order */
   845             // Field[] field = ObjectStreamClass_1_3_1.getDeclaredFields(cl);
   847             ObjectStreamField[] fields = osc.getFields();
   849             // Must make sure that the Field array we allocate
   850             // below is exactly the right size.  Bug fix for
   851             // 4397133.
   852             int numNonNullFields = 0;
   853             for (int i = 0; i < fields.length; i++)
   854                 if (fields[i].getField() != null)
   855                     numNonNullFields++;
   857             Field [] field = new java.lang.reflect.Field[numNonNullFields];
   858             for (int i = 0, fieldNum = 0; i < fields.length; i++) {
   859                 if (fields[i].getField() != null) {
   860                     field[fieldNum++] = fields[i].getField();
   861                 }
   862             }
   864             if (field.length > 1)
   865                 Arrays.sort(field, compareMemberByName);
   867             for (int i = 0; i < field.length; i++) {
   868                 Field f = field[i];
   870                                 /* Include in the hash all fields except those that are
   871                                  * transient
   872                                  */
   873                 int m = f.getModifiers();
   874                 //Serial 6
   875                 //if (Modifier.isTransient(m) || Modifier.isStatic(m))
   876                 // spec reference 00-01-06.pdf, 1.3.5.6, states non-static
   877                 // non-transient, public fields are mapped to Java IDL.
   878                 //
   879                 // Here's the quote from the first paragraph:
   880                 // Java non-static non-transient public fields are mapped to
   881                 // OMG IDL public data members, and other Java fields are
   882                 // not mapped.
   884                 // if (Modifier.isTransient(m) || Modifier.isStatic(m))
   885                 //     continue;
   887                 data.writeUTF(f.getName());
   888                 data.writeUTF(getSignature(f.getType()));
   889             }
   891             /* Compute the hash value for this class.
   892              * Use only the first 64 bits of the hash.
   893              */
   894             data.flush();
   895             byte hasharray[] = md.digest();
   896             // int minimum = Math.min(8, hasharray.length);
   897             // SerialBug 3: SHA computation is wrong; for loop reversed
   898             //for (int i = minimum; i > 0; i--)
   899             for (int i = 0; i < Math.min(8, hasharray.length); i++) {
   900                 h += (long)(hasharray[i] & 255) << (i * 8);
   901             }
   902         } catch (IOException ignore) {
   903             /* can't happen, but be deterministic anyway. */
   904             h = -1;
   905         } catch (NoSuchAlgorithmException complain) {
   906             throw new SecurityException(complain.getMessage());
   907         }
   908         return h;
   909     }
   911     /**
   912      * Compute the JVM signature for the class.
   913      */
   914     static String getSignature(Class<?> clazz) {
   915         String type = null;
   916         if (clazz.isArray()) {
   917             Class<?> cl = clazz;
   918             int dimensions = 0;
   919             while (cl.isArray()) {
   920                 dimensions++;
   921                 cl = cl.getComponentType();
   922             }
   923             StringBuffer sb = new StringBuffer();
   924             for (int i = 0; i < dimensions; i++) {
   925                 sb.append("[");
   926             }
   927             sb.append(getSignature(cl));
   928             type = sb.toString();
   929         } else if (clazz.isPrimitive()) {
   930             if (clazz == Integer.TYPE) {
   931                 type = "I";
   932             } else if (clazz == Byte.TYPE) {
   933                 type = "B";
   934             } else if (clazz == Long.TYPE) {
   935                 type = "J";
   936             } else if (clazz == Float.TYPE) {
   937                 type = "F";
   938             } else if (clazz == Double.TYPE) {
   939                 type = "D";
   940             } else if (clazz == Short.TYPE) {
   941                 type = "S";
   942             } else if (clazz == Character.TYPE) {
   943                 type = "C";
   944             } else if (clazz == Boolean.TYPE) {
   945                 type = "Z";
   946             } else if (clazz == Void.TYPE) {
   947                 type = "V";
   948             }
   949         } else {
   950             type = "L" + clazz.getName().replace('.', '/') + ";";
   951         }
   952         return type;
   953     }
   955     /*
   956      * Compute the JVM method descriptor for the method.
   957      */
   958     static String getSignature(Method meth) {
   959         StringBuffer sb = new StringBuffer();
   961         sb.append("(");
   963         Class<?>[] params = meth.getParameterTypes(); // avoid clone
   964         for (int j = 0; j < params.length; j++) {
   965             sb.append(getSignature(params[j]));
   966         }
   967         sb.append(")");
   968         sb.append(getSignature(meth.getReturnType()));
   969         return sb.toString();
   970     }
   972     /*
   973      * Compute the JVM constructor descriptor for the constructor.
   974      */
   975     static String getSignature(Constructor cons) {
   976         StringBuffer sb = new StringBuffer();
   978         sb.append("(");
   980         Class<?>[] params = cons.getParameterTypes(); // avoid clone
   981         for (int j = 0; j < params.length; j++) {
   982             sb.append(getSignature(params[j]));
   983         }
   984         sb.append(")V");
   985         return sb.toString();
   986     }
   988     /*
   989      * Cache of Class -> ClassDescriptor Mappings.
   990      */
   991     static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
   993     /*
   994      * findDescriptorFor a Class.  This looks in the cache for a
   995      * mapping from Class -> ObjectStreamClass mappings.  The hashCode
   996      * of the Class is used for the lookup since the Class is the key.
   997      * The entries are extended from java.lang.ref.SoftReference so the
   998      * gc will be able to free them if needed.
   999      */
  1000     private static ObjectStreamClass_1_3_1 findDescriptorFor(Class<?> cl) {
  1002         int hash = cl.hashCode();
  1003         int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1004         ObjectStreamClassEntry e;
  1005         ObjectStreamClassEntry prev;
  1007         /* Free any initial entries whose refs have been cleared */
  1008         while ((e = descriptorFor[index]) != null && e.get() == null) {
  1009             descriptorFor[index] = e.next;
  1012         /* Traverse the chain looking for a descriptor with ofClass == cl.
  1013          * unlink entries that are unresolved.
  1014          */
  1015         prev = e;
  1016         while (e != null ) {
  1017             ObjectStreamClass_1_3_1 desc = (ObjectStreamClass_1_3_1)(e.get());
  1018             if (desc == null) {
  1019                 // This entry has been cleared,  unlink it
  1020                 prev.next = e.next;
  1021             } else {
  1022                 if (desc.ofClass == cl)
  1023                     return desc;
  1024                 prev = e;
  1026             e = e.next;
  1028         return null;
  1031     /*
  1032      * insertDescriptorFor a Class -> ObjectStreamClass_1_3_1 mapping.
  1033      */
  1034     private static void insertDescriptorFor(ObjectStreamClass_1_3_1 desc) {
  1035         // Make sure not already present
  1036         if (findDescriptorFor(desc.ofClass) != null) {
  1037             return;
  1040         int hash = desc.ofClass.hashCode();
  1041         int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1042         ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
  1043         e.next = descriptorFor[index];
  1044         descriptorFor[index] = e;
  1047     private static Field[] getDeclaredFields(final Class clz) {
  1048         return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
  1049             public Object run() {
  1050                 return clz.getDeclaredFields();
  1052         });
  1056     /*
  1057      * The name of this descriptor
  1058      */
  1059     private String name;
  1061     /*
  1062      * The descriptor of the supertype.
  1063      */
  1064     private ObjectStreamClass_1_3_1 superclass;
  1066     /*
  1067      * Flags for Serializable and Externalizable.
  1068      */
  1069     private boolean serializable;
  1070     private boolean externalizable;
  1072     /*
  1073      * Array of persistent fields of this class, sorted by
  1074      * type and name.
  1075      */
  1076     private ObjectStreamField[] fields;
  1078     /*
  1079      * Class that is a descriptor for in this virtual machine.
  1080      */
  1081     private Class<?> ofClass;
  1083     /*
  1084      * True if descriptor for a proxy class.
  1085      */
  1086     boolean forProxyClass;
  1089     /*
  1090      * SerialVersionUID for this class.
  1091      */
  1092     private long suid = kDefaultUID;
  1093     private String suidStr = null;
  1095     /*
  1096      * Actual (computed) SerialVersionUID for this class.
  1097      */
  1098     private long actualSuid = kDefaultUID;
  1099     private String actualSuidStr = null;
  1101     /*
  1102      * The total number of bytes of primitive fields.
  1103      * The total number of object fields.
  1104      */
  1105     int primBytes;
  1106     int objFields;
  1108     /* Internal lock object. */
  1109     private Object lock = new Object();
  1111     /* True if this class has/had a writeObject method */
  1112     private boolean hasWriteObjectMethod;
  1114     /* In JDK 1.1, external data was not written in block mode.
  1115      * As of JDK 1.2, external data is written in block data mode. This
  1116      * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
  1118      * @since JDK 1.2
  1119      */
  1120     private boolean hasExternalizableBlockData;
  1121     Method writeObjectMethod;
  1122     Method readObjectMethod;
  1123     private transient Method writeReplaceObjectMethod;
  1124     private transient Method readResolveObjectMethod;
  1126     /*
  1127      * ObjectStreamClass_1_3_1 that this one was built from.
  1128      */
  1129     private ObjectStreamClass_1_3_1 localClassDesc;
  1131     /* Get the private static final field for serial version UID */
  1132     // private static native long getSerialVersionUIDField(Class cl);
  1134     /** use serialVersionUID from JDK 1.1. for interoperability */
  1135     private static final long serialVersionUID = -6120832682080437368L;
  1137     /**
  1138      * Set serialPersistentFields of a Serializable class to this value to
  1139      * denote that the class has no Serializable fields.
  1140      */
  1141     public static final ObjectStreamField[] NO_FIELDS =
  1142         new ObjectStreamField[0];
  1144     /*
  1145      * Entries held in the Cache of known ObjectStreamClass_1_3_1 objects.
  1146      * Entries are chained together with the same hash value (modulo array size).
  1147      */
  1148     private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
  1150         ObjectStreamClassEntry(ObjectStreamClass_1_3_1 c) {
  1151             //super(c);
  1152             this.c = c;
  1154         ObjectStreamClassEntry next;
  1156         public Object get()
  1158             return c;
  1160         private ObjectStreamClass_1_3_1 c;
  1163     /*
  1164      * Comparator object for Classes and Interfaces
  1165      */
  1166     private static Comparator compareClassByName =
  1167         new CompareClassByName();
  1169     private static class CompareClassByName implements Comparator {
  1170         public int compare(Object o1, Object o2) {
  1171             Class<?> c1 = (Class)o1;
  1172             Class<?> c2 = (Class)o2;
  1173             return (c1.getName()).compareTo(c2.getName());
  1177     /*
  1178      * Comparator object for Members, Fields, and Methods
  1179      */
  1180     private static Comparator compareMemberByName =
  1181         new CompareMemberByName();
  1183     private static class CompareMemberByName implements Comparator {
  1184         public int compare(Object o1, Object o2) {
  1185             String s1 = ((Member)o1).getName();
  1186             String s2 = ((Member)o2).getName();
  1188             if (o1 instanceof Method) {
  1189                 s1 += getSignature((Method)o1);
  1190                 s2 += getSignature((Method)o2);
  1191             } else if (o1 instanceof Constructor) {
  1192                 s1 += getSignature((Constructor)o1);
  1193                 s2 += getSignature((Constructor)o2);
  1195             return s1.compareTo(s2);
  1199     /* It is expensive to recompute a method or constructor signature
  1200        many times, so compute it only once using this data structure. */
  1201     private static class MethodSignature implements Comparator {
  1202         Member member;
  1203         String signature;      // cached parameter signature
  1205         /* Given an array of Method or Constructor members,
  1206            return a sorted array of the non-private members.*/
  1207         /* A better implementation would be to implement the returned data
  1208            structure as an insertion sorted link list.*/
  1209         static MethodSignature[] removePrivateAndSort(Member[] m) {
  1210             int numNonPrivate = 0;
  1211             for (int i = 0; i < m.length; i++) {
  1212                 if (! Modifier.isPrivate(m[i].getModifiers())) {
  1213                     numNonPrivate++;
  1216             MethodSignature[] cm = new MethodSignature[numNonPrivate];
  1217             int cmi = 0;
  1218             for (int i = 0; i < m.length; i++) {
  1219                 if (! Modifier.isPrivate(m[i].getModifiers())) {
  1220                     cm[cmi] = new MethodSignature(m[i]);
  1221                     cmi++;
  1224             if (cmi > 0)
  1225                 Arrays.sort(cm, cm[0]);
  1226             return cm;
  1229         /* Assumes that o1 and o2 are either both methods
  1230            or both constructors.*/
  1231         public int compare(Object o1, Object o2) {
  1232             /* Arrays.sort calls compare when o1 and o2 are equal.*/
  1233             if (o1 == o2)
  1234                 return 0;
  1236             MethodSignature c1 = (MethodSignature)o1;
  1237             MethodSignature c2 = (MethodSignature)o2;
  1239             int result;
  1240             if (isConstructor()) {
  1241                 result = c1.signature.compareTo(c2.signature);
  1242             } else { // is a Method.
  1243                 result = c1.member.getName().compareTo(c2.member.getName());
  1244                 if (result == 0)
  1245                     result = c1.signature.compareTo(c2.signature);
  1247             return result;
  1250         final private boolean isConstructor() {
  1251             return member instanceof Constructor;
  1253         private MethodSignature(Member m) {
  1254             member = m;
  1255             if (isConstructor()) {
  1256                 signature = ObjectStreamClass_1_3_1.getSignature((Constructor)m);
  1257             } else {
  1258                 signature = ObjectStreamClass_1_3_1.getSignature((Method)m);

mercurial