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

Tue, 06 Nov 2012 15:50:14 +0000

author
coffeys
date
Tue, 06 Nov 2012 15:50:14 +0000
changeset 446
f4f39d873b9a
parent 158
91006f157c46
child 615
8b0b643ffd42
permissions
-rw-r--r--

7201066: Change modifiers on unused fields
Reviewed-by: alanb, skoivu

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

mercurial