Home | History | Annotate | Download | only in io
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.io;
     19 
     20 import java.lang.ref.SoftReference;
     21 import java.lang.reflect.Constructor;
     22 import java.lang.reflect.Field;
     23 import java.lang.reflect.Method;
     24 import java.lang.reflect.Modifier;
     25 import java.lang.reflect.Proxy;
     26 import java.nio.ByteOrder;
     27 import java.security.MessageDigest;
     28 import java.security.NoSuchAlgorithmException;
     29 import java.util.ArrayList;
     30 import java.util.Arrays;
     31 import java.util.Comparator;
     32 import java.util.HashMap;
     33 import java.util.List;
     34 import java.util.WeakHashMap;
     35 import libcore.io.Memory;
     36 import libcore.util.EmptyArray;
     37 
     38 /**
     39  * Represents a descriptor for identifying a class during serialization and
     40  * deserialization. Information contained in the descriptor includes the name
     41  * and SUID of the class as well as field names and types. Information inherited
     42  * from the superclasses is also taken into account.
     43  *
     44  * @see ObjectOutputStream
     45  * @see ObjectInputStream
     46  * @see java.lang.Class
     47  */
     48 public class ObjectStreamClass implements Serializable {
     49 
     50     // No need to compute the SUID for ObjectStreamClass, just use the value
     51     // below
     52     private static final long serialVersionUID = -6120832682080437368L;
     53 
     54     // Name of the field that contains the SUID value (if present)
     55     private static final String UID_FIELD_NAME = "serialVersionUID";
     56 
     57     static final long CONSTRUCTOR_IS_NOT_RESOLVED = -1;
     58 
     59     private static final int CLASS_MODIFIERS_MASK = Modifier.PUBLIC | Modifier.FINAL |
     60             Modifier.INTERFACE | Modifier.ABSTRACT;
     61 
     62     private static final int FIELD_MODIFIERS_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
     63             Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
     64             Modifier.TRANSIENT;
     65 
     66     private static final int METHOD_MODIFIERS_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
     67             Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED |
     68             Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT;
     69 
     70     private static final Class<?>[] READ_PARAM_TYPES = new Class[] { ObjectInputStream.class };
     71     private static final Class<?>[] WRITE_PARAM_TYPES = new Class[] { ObjectOutputStream.class };
     72 
     73     /**
     74      * Constant indicating that the class has no Serializable fields.
     75      */
     76     public static final ObjectStreamField[] NO_FIELDS = new ObjectStreamField[0];
     77 
     78     /*
     79      * used to fetch field serialPersistentFields and checking its type
     80      */
     81     static final Class<?> ARRAY_OF_FIELDS;
     82 
     83     static {
     84         try {
     85             ARRAY_OF_FIELDS = Class.forName("[Ljava.io.ObjectStreamField;");
     86         } catch (ClassNotFoundException e) {
     87             // This should not happen
     88             throw new AssertionError(e);
     89         }
     90     }
     91 
     92     private static final String CLINIT_NAME = "<clinit>";
     93 
     94     private static final int CLINIT_MODIFIERS = Modifier.STATIC;
     95 
     96     private static final String CLINIT_SIGNATURE = "()V";
     97 
     98     // Used to determine if an object is Serializable or Externalizable
     99     private static final Class<Serializable> SERIALIZABLE = Serializable.class;
    100 
    101     private static final Class<Externalizable> EXTERNALIZABLE = Externalizable.class;
    102 
    103     // Used to test if the object is a String or a class.
    104     static final Class<String> STRINGCLASS = String.class;
    105 
    106     static final Class<?> CLASSCLASS = Class.class;
    107 
    108     static final Class<ObjectStreamClass> OBJECTSTREAMCLASSCLASS = ObjectStreamClass.class;
    109 
    110     private transient Method methodWriteReplace;
    111 
    112     private transient Method methodReadResolve;
    113 
    114     private transient Method methodWriteObject;
    115 
    116     private transient Method methodReadObject;
    117 
    118     private transient Method methodReadObjectNoData;
    119 
    120     /**
    121      * Indicates whether the class properties resolved
    122      *
    123      * @see #resolveProperties()
    124      */
    125     private transient boolean arePropertiesResolved;
    126 
    127     /**
    128      * Cached class properties
    129      *
    130      * @see #resolveProperties()
    131      * @see #isSerializable()
    132      * @see #isExternalizable()
    133      * @see #isProxy()
    134      * @see #isEnum()
    135      */
    136     private transient boolean isSerializable;
    137     private transient boolean isExternalizable;
    138     private transient boolean isProxy;
    139     private transient boolean isEnum;
    140 
    141     // ClassDesc //
    142 
    143     // Name of the class this descriptor represents
    144     private transient String className;
    145 
    146     // Corresponding loaded class with the name above
    147     private transient Class<?> resolvedClass;
    148 
    149     private transient Class<?> resolvedConstructorClass;
    150     private transient int resolvedConstructorMethodId;
    151 
    152     // Serial version UID of the class the descriptor represents
    153     private transient long svUID;
    154 
    155     // ClassDescInfo //
    156 
    157     // Any combination of SC_WRITE_METHOD, SC_SERIALIZABLE and SC_EXTERNALIZABLE
    158     // (see ObjectStreamConstants)
    159     private transient byte flags;
    160 
    161     // Descriptor for the superclass of the class associated with this
    162     // descriptor
    163     private transient ObjectStreamClass superclass;
    164 
    165     // Array of ObjectStreamField (see below) describing the fields of this
    166     // class
    167     private transient ObjectStreamField[] fields;
    168 
    169     // Array of ObjectStreamField describing the serialized fields of this class
    170     private transient ObjectStreamField[] loadFields;
    171 
    172     // ObjectStreamField doesn't override hashCode or equals, so this is equivalent to an
    173     // IdentityHashMap, which is fine for our purposes.
    174     private transient HashMap<ObjectStreamField, Field> reflectionFields =
    175             new HashMap<ObjectStreamField, Field>();
    176 
    177     // MethodID for deserialization constructor
    178     private transient long constructor = CONSTRUCTOR_IS_NOT_RESOLVED;
    179 
    180     void setConstructor(long newConstructor) {
    181         constructor = newConstructor;
    182     }
    183 
    184     long getConstructor() {
    185         return constructor;
    186     }
    187 
    188     Field getReflectionField(ObjectStreamField osf) {
    189         synchronized (reflectionFields) {
    190             Field field = reflectionFields.get(osf);
    191             if (field != null) {
    192                 return field;
    193             }
    194         }
    195 
    196         try {
    197             Class<?> declaringClass = forClass();
    198             Field field = declaringClass.getDeclaredField(osf.getName());
    199             field.setAccessible(true);
    200             synchronized (reflectionFields) {
    201                 reflectionFields.put(osf, field);
    202             }
    203             return reflectionFields.get(osf);
    204         } catch (NoSuchFieldException ex) {
    205             // The caller messed up. We'll return null and won't try to resolve this again.
    206             return null;
    207         }
    208     }
    209 
    210     /*
    211      * If an ObjectStreamClass describes an Externalizable class, it (the
    212      * descriptor) should not have field descriptors (ObjectStreamField) at all.
    213      * The ObjectStreamClass that gets saved should simply have no field info.
    214      * This is a footnote in page 1511 (class Serializable) of "The Java Class
    215      * Libraries, Second Edition, Vol. I".
    216      */
    217 
    218     /**
    219      * Constructs a new instance of this class.
    220      */
    221     ObjectStreamClass() {
    222     }
    223 
    224     /**
    225      * Compute class descriptor for a given class <code>cl</code>.
    226      *
    227      * @param cl
    228      *            a java.langClass for which to compute the corresponding
    229      *            descriptor
    230      * @return the computer class descriptor
    231      */
    232     private static ObjectStreamClass createClassDesc(Class<?> cl) {
    233 
    234         ObjectStreamClass result = new ObjectStreamClass();
    235 
    236         boolean isArray = cl.isArray();
    237         boolean serializable = isSerializable(cl);
    238         boolean externalizable = isExternalizable(cl);
    239 
    240         result.isSerializable = serializable;
    241         result.isExternalizable = externalizable;
    242 
    243         // Now we fill in the values
    244         result.setName(cl.getName());
    245         result.setClass(cl);
    246         Class<?> superclass = cl.getSuperclass();
    247         if (superclass != null) {
    248             result.setSuperclass(lookup(superclass));
    249         }
    250 
    251         Field[] declaredFields = null;
    252 
    253         // Compute the SUID
    254         if (serializable || externalizable) {
    255             if (result.isEnum() || result.isProxy()) {
    256                 result.setSerialVersionUID(0L);
    257             } else {
    258                 declaredFields = cl.getDeclaredFields();
    259                 result.setSerialVersionUID(computeSerialVersionUID(cl, declaredFields));
    260             }
    261         }
    262 
    263         // Serializables need field descriptors
    264         if (serializable && !isArray) {
    265             if (declaredFields == null) {
    266                 declaredFields = cl.getDeclaredFields();
    267             }
    268             result.buildFieldDescriptors(declaredFields);
    269         } else {
    270             // Externalizables or arrays do not need FieldDesc info
    271             result.setFields(NO_FIELDS);
    272         }
    273 
    274         // Copy all fields to loadFields - they should be read by default in
    275         // ObjectInputStream.defaultReadObject() method
    276         ObjectStreamField[] fields = result.getFields();
    277 
    278         if (fields != null) {
    279             ObjectStreamField[] loadFields = new ObjectStreamField[fields.length];
    280 
    281             for (int i = 0; i < fields.length; ++i) {
    282                 loadFields[i] = new ObjectStreamField(fields[i].getName(),
    283                         fields[i].getType(), fields[i].isUnshared());
    284 
    285                 // resolve type string to init typeString field in
    286                 // ObjectStreamField
    287                 loadFields[i].getTypeString();
    288             }
    289             result.setLoadFields(loadFields);
    290         }
    291 
    292         byte flags = 0;
    293         if (externalizable) {
    294             flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
    295             flags |= ObjectStreamConstants.SC_BLOCK_DATA; // use protocol version 2 by default
    296         } else if (serializable) {
    297             flags |= ObjectStreamConstants.SC_SERIALIZABLE;
    298         }
    299         result.methodWriteReplace = findMethod(cl, "writeReplace");
    300         result.methodReadResolve = findMethod(cl, "readResolve");
    301         result.methodWriteObject = findPrivateMethod(cl, "writeObject", WRITE_PARAM_TYPES);
    302         result.methodReadObject = findPrivateMethod(cl, "readObject", READ_PARAM_TYPES);
    303         result.methodReadObjectNoData = findPrivateMethod(cl, "readObjectNoData", EmptyArray.CLASS);
    304         if (result.hasMethodWriteObject()) {
    305             flags |= ObjectStreamConstants.SC_WRITE_METHOD;
    306         }
    307         result.setFlags(flags);
    308 
    309         return result;
    310     }
    311 
    312     /**
    313      * Builds the collection of field descriptors for the receiver
    314      *
    315      * @param declaredFields
    316      *            collection of java.lang.reflect.Field for which to compute
    317      *            field descriptors
    318      */
    319     void buildFieldDescriptors(Field[] declaredFields) {
    320         // We could find the field ourselves in the collection, but calling
    321         // reflect is easier. Optimize if needed.
    322         final Field f = ObjectStreamClass.fieldSerialPersistentFields(this.forClass());
    323         // If we could not find the emulated fields, we'll have to compute
    324         // dumpable fields from reflect fields
    325         boolean useReflectFields = f == null; // Assume we will compute the
    326         // fields to dump based on the
    327         // reflect fields
    328 
    329         ObjectStreamField[] _fields = null;
    330         if (!useReflectFields) {
    331             // The user declared a collection of emulated fields. Use them.
    332             // We have to be able to fetch its value, even if it is private
    333             f.setAccessible(true);
    334             try {
    335                 // static field, pass null
    336                 _fields = (ObjectStreamField[]) f.get(null);
    337             } catch (IllegalAccessException ex) {
    338                 throw new AssertionError(ex);
    339             }
    340         } else {
    341             // Compute collection of dumpable fields based on reflect fields
    342             List<ObjectStreamField> serializableFields =
    343                     new ArrayList<ObjectStreamField>(declaredFields.length);
    344             // Filter, we are only interested in fields that are serializable
    345             for (Field declaredField : declaredFields) {
    346                 int modifiers = declaredField.getModifiers();
    347                 if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
    348                     ObjectStreamField field = new ObjectStreamField(declaredField.getName(),
    349                             declaredField.getType());
    350                     serializableFields.add(field);
    351                 }
    352             }
    353 
    354             if (serializableFields.size() == 0) {
    355                 _fields = NO_FIELDS; // If no serializable fields, share the
    356                 // special value so that users can test
    357             } else {
    358                 _fields = serializableFields.toArray(new ObjectStreamField[serializableFields.size()]);
    359             }
    360         }
    361         Arrays.sort(_fields);
    362         // assign offsets
    363         int primOffset = 0, objectOffset = 0;
    364         for (int i = 0; i < _fields.length; i++) {
    365             Class<?> type = _fields[i].getType();
    366             if (type.isPrimitive()) {
    367                 _fields[i].offset = primOffset;
    368                 primOffset += primitiveSize(type);
    369             } else {
    370                 _fields[i].offset = objectOffset++;
    371             }
    372         }
    373         fields = _fields;
    374     }
    375 
    376     /**
    377      * Compute and return the Serial Version UID of the class {@code cl}.
    378      * The value is computed based on the class name, superclass chain, field
    379      * names, method names, modifiers, etc.
    380      *
    381      * @param cl
    382      *            a java.lang.Class for which to compute the SUID
    383      * @param fields
    384      *            cl.getDeclaredFields(), pre-computed by the caller
    385      * @return the value of SUID of this class
    386      */
    387     private static long computeSerialVersionUID(Class<?> cl, Field[] fields) {
    388         /*
    389          * First we should try to fetch the static slot 'static final long
    390          * serialVersionUID'. If it is defined, return it. If not defined, we
    391          * really need to compute SUID using SHAOutputStream
    392          */
    393         for (int i = 0; i < fields.length; i++) {
    394             final Field field = fields[i];
    395             if (field.getType() == long.class) {
    396                 int modifiers = field.getModifiers();
    397                 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
    398                     if (UID_FIELD_NAME.equals(field.getName())) {
    399                         /*
    400                          * We need to be able to see it even if we have no
    401                          * visibility. That is why we set accessible first (new
    402                          * API in reflect 1.2)
    403                          */
    404                         field.setAccessible(true);
    405                         try {
    406                             // Static field, parameter is ignored
    407                             return field.getLong(null);
    408                         } catch (IllegalAccessException iae) {
    409                             throw new RuntimeException("Error fetching SUID: " + iae);
    410                         }
    411                     }
    412                 }
    413             }
    414         }
    415 
    416         MessageDigest digest;
    417         try {
    418             digest = MessageDigest.getInstance("SHA");
    419         } catch (NoSuchAlgorithmException e) {
    420             throw new Error(e);
    421         }
    422         ByteArrayOutputStream sha = new ByteArrayOutputStream();
    423         try {
    424             DataOutputStream output = new DataOutputStream(sha);
    425             output.writeUTF(cl.getName());
    426             int classModifiers = CLASS_MODIFIERS_MASK & cl.getModifiers();
    427             /*
    428              * Workaround for 1F9LOQO. Arrays are ABSTRACT in JDK, but that is
    429              * not in the specification. Since we want to be compatible for
    430              * X-loading, we have to pretend we have the same shape
    431              */
    432             boolean isArray = cl.isArray();
    433             if (isArray) {
    434                 classModifiers |= Modifier.ABSTRACT;
    435             }
    436             // Required for JDK UID compatibility
    437             if (cl.isInterface() && !Modifier.isPublic(classModifiers)) {
    438                 classModifiers &= ~Modifier.ABSTRACT;
    439             }
    440             output.writeInt(classModifiers);
    441 
    442             /*
    443              * In JDK1.2 arrays implement Cloneable and Serializable but not in
    444              * JDK 1.1.7. So, JDK 1.2 "pretends" arrays have no interfaces when
    445              * computing SHA-1 to be compatible.
    446              */
    447             if (!isArray) {
    448                 // Interface information
    449                 Class<?>[] interfaces = cl.getInterfaces();
    450                 if (interfaces.length > 1) {
    451                     // Only attempt to sort if really needed (saves object
    452                     // creation, etc)
    453                     Comparator<Class<?>> interfaceComparator = new Comparator<Class<?>>() {
    454                         public int compare(Class<?> itf1, Class<?> itf2) {
    455                             return itf1.getName().compareTo(itf2.getName());
    456                         }
    457                     };
    458                     Arrays.sort(interfaces, interfaceComparator);
    459                 }
    460 
    461                 // Dump them
    462                 for (int i = 0; i < interfaces.length; i++) {
    463                     output.writeUTF(interfaces[i].getName());
    464                 }
    465             }
    466 
    467             // Field information
    468             if (fields.length > 1) {
    469                 // Only attempt to sort if really needed (saves object creation,
    470                 // etc)
    471                 Comparator<Field> fieldComparator = new Comparator<Field>() {
    472                     public int compare(Field field1, Field field2) {
    473                         return field1.getName().compareTo(field2.getName());
    474                     }
    475                 };
    476                 Arrays.sort(fields, fieldComparator);
    477             }
    478 
    479             // Dump them
    480             for (int i = 0; i < fields.length; i++) {
    481                 Field field = fields[i];
    482                 int modifiers = field.getModifiers() & FIELD_MODIFIERS_MASK;
    483 
    484                 boolean skip = Modifier.isPrivate(modifiers)
    485                         && (Modifier.isTransient(modifiers) || Modifier
    486                                 .isStatic(modifiers));
    487                 if (!skip) {
    488                     // write name, modifier & "descriptor" of all but private
    489                     // static and private transient
    490                     output.writeUTF(field.getName());
    491                     output.writeInt(modifiers);
    492                     output
    493                             .writeUTF(descriptorForFieldSignature(getFieldSignature(field)));
    494                 }
    495             }
    496 
    497             /*
    498              * Normally constructors come before methods (because <init> <
    499              * anyMethodName). However, <clinit> is an exception. Besides,
    500              * reflect will not let us get to it.
    501              */
    502             if (hasClinit(cl)) {
    503                 // write name, modifier & "descriptor"
    504                 output.writeUTF(CLINIT_NAME);
    505                 output.writeInt(CLINIT_MODIFIERS);
    506                 output.writeUTF(CLINIT_SIGNATURE);
    507             }
    508 
    509             // Constructor information
    510             Constructor<?>[] constructors = cl.getDeclaredConstructors();
    511             if (constructors.length > 1) {
    512                 // Only attempt to sort if really needed (saves object creation,
    513                 // etc)
    514                 Comparator<Constructor<?>> constructorComparator = new Comparator<Constructor<?>>() {
    515                     public int compare(Constructor<?> ctr1, Constructor<?> ctr2) {
    516                         // All constructors have same name, so we sort based on
    517                         // signature
    518                         return (getConstructorSignature(ctr1)
    519                                 .compareTo(getConstructorSignature(ctr2)));
    520                     }
    521                 };
    522                 Arrays.sort(constructors, constructorComparator);
    523             }
    524 
    525             // Dump them
    526             for (int i = 0; i < constructors.length; i++) {
    527                 Constructor<?> constructor = constructors[i];
    528                 int modifiers = constructor.getModifiers()
    529                         & METHOD_MODIFIERS_MASK;
    530                 boolean isPrivate = Modifier.isPrivate(modifiers);
    531                 if (!isPrivate) {
    532                     /*
    533                      * write name, modifier & "descriptor" of all but private
    534                      * ones
    535                      *
    536                      * constructor.getName() returns the constructor name as
    537                      * typed, not the VM name
    538                      */
    539                     output.writeUTF("<init>");
    540                     output.writeInt(modifiers);
    541                     output.writeUTF(descriptorForSignature(
    542                             getConstructorSignature(constructor)).replace('/',
    543                             '.'));
    544                 }
    545             }
    546 
    547             // Method information
    548             Method[] methods = cl.getDeclaredMethods();
    549             if (methods.length > 1) {
    550                 Comparator<Method> methodComparator = new Comparator<Method>() {
    551                     public int compare(Method m1, Method m2) {
    552                         int result = m1.getName().compareTo(m2.getName());
    553                         if (result == 0) {
    554                             // same name, signature will tell which one comes
    555                             // first
    556                             return getMethodSignature(m1).compareTo(
    557                                     getMethodSignature(m2));
    558                         }
    559                         return result;
    560                     }
    561                 };
    562                 Arrays.sort(methods, methodComparator);
    563             }
    564 
    565             // Dump them
    566             for (int i = 0; i < methods.length; i++) {
    567                 Method method = methods[i];
    568                 int modifiers = method.getModifiers() & METHOD_MODIFIERS_MASK;
    569                 boolean isPrivate = Modifier.isPrivate(modifiers);
    570                 if (!isPrivate) {
    571                     // write name, modifier & "descriptor" of all but private
    572                     // ones
    573                     output.writeUTF(method.getName());
    574                     output.writeInt(modifiers);
    575                     output.writeUTF(descriptorForSignature(
    576                             getMethodSignature(method)).replace('/', '.'));
    577                 }
    578             }
    579         } catch (IOException e) {
    580             throw new RuntimeException(e + " computing SHA-1/SUID");
    581         }
    582 
    583         // now compute the UID based on the SHA
    584         byte[] hash = digest.digest(sha.toByteArray());
    585         return Memory.peekLong(hash, 0, ByteOrder.LITTLE_ENDIAN);
    586     }
    587 
    588     /**
    589      * Returns what the serialization specification calls "descriptor" given a
    590      * field signature.
    591      *
    592      * @param signature
    593      *            a field signature
    594      * @return containing the descriptor
    595      */
    596     private static String descriptorForFieldSignature(String signature) {
    597         return signature.replace('.', '/');
    598     }
    599 
    600     /**
    601      * Return what the serialization specification calls "descriptor" given a
    602      * method/constructor signature.
    603      *
    604      * @param signature
    605      *            a method or constructor signature
    606      * @return containing the descriptor
    607      */
    608     private static String descriptorForSignature(String signature) {
    609         return signature.substring(signature.indexOf("("));
    610     }
    611 
    612     /**
    613      * Return the java.lang.reflect.Field {@code serialPersistentFields}
    614      * if class {@code cl} implements it. Return null otherwise.
    615      *
    616      * @param cl
    617      *            a java.lang.Class which to test
    618      * @return {@code java.lang.reflect.Field} if the class has
    619      *         serialPersistentFields {@code null} if the class does not
    620      *         have serialPersistentFields
    621      */
    622     static Field fieldSerialPersistentFields(Class<?> cl) {
    623         try {
    624             Field f = cl.getDeclaredField("serialPersistentFields");
    625             int modifiers = f.getModifiers();
    626             if (Modifier.isStatic(modifiers) && Modifier.isPrivate(modifiers)
    627                     && Modifier.isFinal(modifiers)) {
    628                 if (f.getType() == ARRAY_OF_FIELDS) {
    629                     return f;
    630                 }
    631             }
    632         } catch (NoSuchFieldException nsm) {
    633             // Ignored
    634         }
    635         return null;
    636     }
    637 
    638     /**
    639      * Returns the class (java.lang.Class) for this descriptor.
    640      *
    641      * @return the class in the local VM that this descriptor represents;
    642      *         {@code null} if there is no corresponding class.
    643      */
    644     public Class<?> forClass() {
    645         return resolvedClass;
    646     }
    647 
    648     /**
    649      * Create and return a new instance of class 'instantiationClass'
    650      * using JNI to call the constructor chosen by resolveConstructorClass.
    651      *
    652      * The returned instance may have uninitialized fields, including final fields.
    653      */
    654     Object newInstance(Class<?> instantiationClass) throws InvalidClassException {
    655         resolveConstructorClass(instantiationClass);
    656         return newInstance(instantiationClass, resolvedConstructorMethodId);
    657     }
    658     private static native Object newInstance(Class<?> instantiationClass, int methodId);
    659 
    660     private Class<?> resolveConstructorClass(Class<?> objectClass) throws InvalidClassException {
    661         if (resolvedConstructorClass != null) {
    662             return resolvedConstructorClass;
    663         }
    664 
    665         // The class of the instance may not be the same as the class of the
    666         // constructor to run
    667         // This is the constructor to run if Externalizable
    668         Class<?> constructorClass = objectClass;
    669 
    670         // WARNING - What if the object is serializable and externalizable ?
    671         // Is that possible ?
    672         boolean wasSerializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
    673         if (wasSerializable) {
    674             // Now we must run the constructor of the class just above the
    675             // one that implements Serializable so that slots that were not
    676             // dumped can be initialized properly
    677             while (constructorClass != null && ObjectStreamClass.isSerializable(constructorClass)) {
    678                 constructorClass = constructorClass.getSuperclass();
    679             }
    680         }
    681 
    682         // Fetch the empty constructor, or null if none.
    683         Constructor<?> constructor = null;
    684         if (constructorClass != null) {
    685             try {
    686                 constructor = constructorClass.getDeclaredConstructor(EmptyArray.CLASS);
    687             } catch (NoSuchMethodException ignored) {
    688             }
    689         }
    690 
    691         // Has to have an empty constructor
    692         if (constructor == null) {
    693             String className = constructorClass != null ? constructorClass.getName() : null;
    694             throw new InvalidClassException(className, "IllegalAccessException");
    695         }
    696 
    697         int constructorModifiers = constructor.getModifiers();
    698         boolean isPublic = Modifier.isPublic(constructorModifiers);
    699         boolean isProtected = Modifier.isProtected(constructorModifiers);
    700         boolean isPrivate = Modifier.isPrivate(constructorModifiers);
    701 
    702         // Now we must check if the empty constructor is visible to the
    703         // instantiation class
    704         boolean wasExternalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
    705         if (isPrivate || (wasExternalizable && !isPublic)) {
    706             throw new InvalidClassException(constructorClass.getName(), "IllegalAccessException");
    707         }
    708 
    709         // We know we are testing from a subclass, so the only other case
    710         // where the visibility is not allowed is when the constructor has
    711         // default visibility and the instantiation class is in a different
    712         // package than the constructor class
    713         if (!isPublic && !isProtected) {
    714             // Not public, not private and not protected...means default
    715             // visibility. Check if same package
    716             if (!inSamePackage(constructorClass, objectClass)) {
    717                 throw new InvalidClassException(constructorClass.getName(), "IllegalAccessException");
    718             }
    719         }
    720 
    721         resolvedConstructorClass = constructorClass;
    722         resolvedConstructorMethodId = getConstructorId(resolvedConstructorClass);
    723         return constructorClass;
    724     }
    725     private static native int getConstructorId(Class<?> c);
    726 
    727     /**
    728      * Checks if two classes belong to the same package.
    729      *
    730      * @param c1
    731      *            one of the classes to test.
    732      * @param c2
    733      *            the other class to test.
    734      * @return {@code true} if the two classes belong to the same package,
    735      *         {@code false} otherwise.
    736      */
    737     private boolean inSamePackage(Class<?> c1, Class<?> c2) {
    738         String nameC1 = c1.getName();
    739         String nameC2 = c2.getName();
    740         int indexDotC1 = nameC1.lastIndexOf('.');
    741         int indexDotC2 = nameC2.lastIndexOf('.');
    742         if (indexDotC1 != indexDotC2) {
    743             return false; // cannot be in the same package if indices are not the same
    744         }
    745         if (indexDotC1 == -1) {
    746             return true; // both of them are in default package
    747         }
    748         return nameC1.regionMatches(0, nameC2, 0, indexDotC1);
    749     }
    750 
    751     /**
    752      * Return a String representing the signature for a Constructor {@code c}.
    753      *
    754      * @param c
    755      *            a java.lang.reflect.Constructor for which to compute the
    756      *            signature
    757      * @return the constructor's signature
    758      */
    759     static native String getConstructorSignature(Constructor<?> c);
    760 
    761     /**
    762      * Gets a field descriptor of the class represented by this class
    763      * descriptor.
    764      *
    765      * @param name
    766      *            the name of the desired field.
    767      * @return the field identified by {@code name} or {@code null} if there is
    768      *         no such field.
    769      */
    770     public ObjectStreamField getField(String name) {
    771         ObjectStreamField[] allFields = getFields();
    772         for (int i = 0; i < allFields.length; i++) {
    773             ObjectStreamField f = allFields[i];
    774             if (f.getName().equals(name)) {
    775                 return f;
    776             }
    777         }
    778         return null;
    779     }
    780 
    781     /**
    782      * Returns the collection of field descriptors for the fields of the
    783      * corresponding class
    784      *
    785      * @return the receiver's collection of declared fields for the class it
    786      *         represents
    787      */
    788     ObjectStreamField[] fields() {
    789         if (fields == null) {
    790             Class<?> forCl = forClass();
    791             if (forCl != null && isSerializable() && !forCl.isArray()) {
    792                 buildFieldDescriptors(forCl.getDeclaredFields());
    793             } else {
    794                 // Externalizables or arrays do not need FieldDesc info
    795                 setFields(NO_FIELDS);
    796             }
    797         }
    798         return fields;
    799     }
    800 
    801     /**
    802      * Returns a collection of field descriptors for the serialized fields of
    803      * the class represented by this class descriptor.
    804      *
    805      * @return an array of field descriptors or an array of length zero if there
    806      *         are no fields in this descriptor's class.
    807      */
    808     public ObjectStreamField[] getFields() {
    809         copyFieldAttributes();
    810         return loadFields == null ? fields().clone() : loadFields.clone();
    811     }
    812 
    813     private transient volatile List<ObjectStreamClass> cachedHierarchy;
    814 
    815     List<ObjectStreamClass> getHierarchy() {
    816         List<ObjectStreamClass> result = cachedHierarchy;
    817         if (result == null) {
    818             cachedHierarchy = result = makeHierarchy();
    819         }
    820         return result;
    821     }
    822 
    823     private List<ObjectStreamClass> makeHierarchy() {
    824         ArrayList<ObjectStreamClass> result = new ArrayList<ObjectStreamClass>();
    825         for (ObjectStreamClass osc = this; osc != null; osc = osc.getSuperclass()) {
    826             result.add(0, osc);
    827         }
    828         return result;
    829     }
    830 
    831     /**
    832      * If a Class uses "serialPersistentFields" to define the serialized fields,
    833      * this.loadFields cannot get the "unshared" information when deserializing
    834      * fields using current implementation of ObjectInputStream. This method
    835      * provides a way to copy the "unshared" attribute from this.fields.
    836      *
    837      */
    838     private void copyFieldAttributes() {
    839         if ((loadFields == null) || fields == null) {
    840             return;
    841         }
    842 
    843         for (int i = 0; i < loadFields.length; i++) {
    844             ObjectStreamField loadField = loadFields[i];
    845             String name = loadField.getName();
    846             for (int j = 0; j < fields.length; j++) {
    847                 ObjectStreamField field = fields[j];
    848                 if (name.equals(field.getName())) {
    849                     loadField.setUnshared(field.isUnshared());
    850                     loadField.setOffset(field.getOffset());
    851                     break;
    852                 }
    853             }
    854         }
    855     }
    856 
    857     /**
    858      * Returns the collection of field descriptors for the input fields of the
    859      * corresponding class
    860      *
    861      * @return the receiver's collection of input fields for the class it
    862      *         represents
    863      */
    864     ObjectStreamField[] getLoadFields() {
    865         return loadFields;
    866     }
    867 
    868     /**
    869      * Return a String representing the signature for a field {@code f}.
    870      *
    871      * @param f
    872      *            a java.lang.reflect.Field for which to compute the signature
    873      * @return the field's signature
    874      */
    875     private static native String getFieldSignature(Field f);
    876 
    877     /**
    878      * Returns the flags for this descriptor, where possible combined values are
    879      *
    880      * ObjectStreamConstants.SC_WRITE_METHOD
    881      * ObjectStreamConstants.SC_SERIALIZABLE
    882      * ObjectStreamConstants.SC_EXTERNALIZABLE
    883      *
    884      * @return byte the receiver's flags for the class it represents
    885      */
    886     byte getFlags() {
    887         return flags;
    888     }
    889 
    890     /**
    891      * Return a String representing the signature for a method {@code m}.
    892      *
    893      * @param m
    894      *            a java.lang.reflect.Method for which to compute the signature
    895      * @return the method's signature
    896      */
    897     static native String getMethodSignature(Method m);
    898 
    899     /**
    900      * Returns the name of the class represented by this descriptor.
    901      *
    902      * @return the fully qualified name of the class this descriptor represents.
    903      */
    904     public String getName() {
    905         return className;
    906     }
    907 
    908     /**
    909      * Returns the Serial Version User ID of the class represented by this
    910      * descriptor.
    911      *
    912      * @return the SUID for the class represented by this descriptor.
    913      */
    914     public long getSerialVersionUID() {
    915         return svUID;
    916     }
    917 
    918     /**
    919      * Returns the descriptor (ObjectStreamClass) of the superclass of the class
    920      * represented by the receiver.
    921      *
    922      * @return an ObjectStreamClass representing the superclass of the class
    923      *         represented by the receiver.
    924      */
    925     ObjectStreamClass getSuperclass() {
    926         return superclass;
    927     }
    928 
    929     /**
    930      * Return true if the given class {@code cl} has the
    931      * compiler-generated method {@code clinit}. Even though it is
    932      * compiler-generated, it is used by the serialization code to compute SUID.
    933      * This is unfortunate, since it may depend on compiler optimizations in
    934      * some cases.
    935      *
    936      * @param cl
    937      *            a java.lang.Class which to test
    938      * @return {@code true} if the class has <clinit> {@code false}
    939      *         if the class does not have <clinit>
    940      */
    941     private static native boolean hasClinit(Class<?> cl);
    942 
    943     /**
    944      * Return true if instances of class {@code cl} are Externalizable,
    945      * false otherwise.
    946      *
    947      * @param cl
    948      *            a java.lang.Class which to test
    949      * @return {@code true} if instances of the class are Externalizable
    950      *         {@code false} if instances of the class are not
    951      *         Externalizable
    952      *
    953      * @see Object#hashCode
    954      */
    955     static boolean isExternalizable(Class<?> cl) {
    956         return EXTERNALIZABLE.isAssignableFrom(cl);
    957     }
    958 
    959     /**
    960      * Return true if the type code
    961      * <code>typecode<code> describes a primitive type
    962      *
    963      * @param typecode a char describing the typecode
    964      * @return {@code true} if the typecode represents a primitive type
    965      * {@code false} if the typecode represents an Object type (including arrays)
    966      *
    967      * @see Object#hashCode
    968      */
    969     static boolean isPrimitiveType(char typecode) {
    970         return !(typecode == '[' || typecode == 'L');
    971     }
    972 
    973     /**
    974      * Return true if instances of class {@code cl} are Serializable,
    975      * false otherwise.
    976      *
    977      * @param cl
    978      *            a java.lang.Class which to test
    979      * @return {@code true} if instances of the class are Serializable
    980      *         {@code false} if instances of the class are not
    981      *         Serializable
    982      *
    983      * @see Object#hashCode
    984      */
    985     static boolean isSerializable(Class<?> cl) {
    986         return SERIALIZABLE.isAssignableFrom(cl);
    987     }
    988 
    989     /**
    990      * Resolves the class properties, if they weren't already
    991      */
    992     private void resolveProperties() {
    993         if (arePropertiesResolved) {
    994             return;
    995         }
    996 
    997         Class<?> cl = forClass();
    998         isProxy = Proxy.isProxyClass(cl);
    999         isEnum = Enum.class.isAssignableFrom(cl);
   1000         isSerializable = isSerializable(cl);
   1001         isExternalizable = isExternalizable(cl);
   1002 
   1003         arePropertiesResolved = true;
   1004     }
   1005 
   1006     boolean isSerializable() {
   1007         resolveProperties();
   1008         return isSerializable;
   1009     }
   1010 
   1011     boolean isExternalizable() {
   1012         resolveProperties();
   1013         return isExternalizable;
   1014     }
   1015 
   1016     boolean isProxy() {
   1017         resolveProperties();
   1018         return isProxy;
   1019     }
   1020 
   1021     boolean isEnum() {
   1022         resolveProperties();
   1023         return isEnum;
   1024     }
   1025 
   1026     /**
   1027      * Returns the descriptor for a serializable class.
   1028      * Returns null if the class doesn't implement {@code Serializable} or {@code Externalizable}.
   1029      *
   1030      * @param cl
   1031      *            a java.lang.Class for which to obtain the corresponding
   1032      *            descriptor
   1033      * @return the corresponding descriptor if the class is serializable or
   1034      *         externalizable; null otherwise.
   1035      */
   1036     public static ObjectStreamClass lookup(Class<?> cl) {
   1037         ObjectStreamClass osc = lookupStreamClass(cl);
   1038         return (osc.isSerializable() || osc.isExternalizable()) ? osc : null;
   1039     }
   1040 
   1041     /**
   1042      * Returns the descriptor for any class, whether or not the class
   1043      * implements Serializable or Externalizable.
   1044      *
   1045      * @param cl
   1046      *            a java.lang.Class for which to obtain the corresponding
   1047      *            descriptor
   1048      * @return the descriptor
   1049      * @since 1.6
   1050      */
   1051     public static ObjectStreamClass lookupAny(Class<?> cl) {
   1052         return lookupStreamClass(cl);
   1053     }
   1054 
   1055     /**
   1056      * Return the descriptor (ObjectStreamClass) corresponding to the class
   1057      * {@code cl}. Returns an ObjectStreamClass even if instances of the
   1058      * class cannot be serialized
   1059      *
   1060      * @param cl
   1061      *            a java.langClass for which to obtain the corresponding
   1062      *            descriptor
   1063      * @return the corresponding descriptor
   1064      */
   1065     static ObjectStreamClass lookupStreamClass(Class<?> cl) {
   1066         WeakHashMap<Class<?>, ObjectStreamClass> tlc = getCache();
   1067         ObjectStreamClass cachedValue = tlc.get(cl);
   1068         if (cachedValue == null) {
   1069             cachedValue = createClassDesc(cl);
   1070             tlc.put(cl, cachedValue);
   1071         }
   1072         return cachedValue;
   1073 
   1074     }
   1075 
   1076     /**
   1077      * A ThreadLocal cache for lookupStreamClass, with the possibility of discarding the thread
   1078      * local storage content when the heap is exhausted.
   1079      */
   1080     private static SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>> storage =
   1081             new SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>>(null);
   1082 
   1083     private static WeakHashMap<Class<?>, ObjectStreamClass> getCache() {
   1084         ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>> tls = storage.get();
   1085         if (tls == null) {
   1086             tls = new ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>() {
   1087                 public WeakHashMap<Class<?>, ObjectStreamClass> initialValue() {
   1088                     return new WeakHashMap<Class<?>, ObjectStreamClass>();
   1089                 }
   1090             };
   1091             storage = new SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>>(tls);
   1092         }
   1093         return tls.get();
   1094     }
   1095 
   1096     /**
   1097      * Return the java.lang.reflect.Method if class <code>cl</code> implements
   1098      * <code>methodName</code> . Return null otherwise.
   1099      *
   1100      * @param cl
   1101      *            a java.lang.Class which to test
   1102      * @return <code>java.lang.reflect.Method</code> if the class implements
   1103      *         writeReplace <code>null</code> if the class does not implement
   1104      *         writeReplace
   1105      */
   1106     static Method findMethod(Class<?> cl, String methodName) {
   1107         Class<?> search = cl;
   1108         Method method = null;
   1109         while (search != null) {
   1110             try {
   1111                 method = search.getDeclaredMethod(methodName, (Class[]) null);
   1112                 if (search == cl
   1113                         || (method.getModifiers() & Modifier.PRIVATE) == 0) {
   1114                     method.setAccessible(true);
   1115                     return method;
   1116                 }
   1117             } catch (NoSuchMethodException nsm) {
   1118             }
   1119             search = search.getSuperclass();
   1120         }
   1121         return null;
   1122     }
   1123 
   1124     /**
   1125      * Return the java.lang.reflect.Method if class <code>cl</code> implements
   1126      * private <code>methodName</code> . Return null otherwise.
   1127      *
   1128      * @param cl
   1129      *            a java.lang.Class which to test
   1130      * @return {@code java.lang.reflect.Method} if the class implements
   1131      *         writeReplace {@code null} if the class does not implement
   1132      *         writeReplace
   1133      */
   1134     static Method findPrivateMethod(Class<?> cl, String methodName,
   1135             Class<?>[] param) {
   1136         try {
   1137             Method method = cl.getDeclaredMethod(methodName, param);
   1138             if (Modifier.isPrivate(method.getModifiers()) && method.getReturnType() == void.class) {
   1139                 method.setAccessible(true);
   1140                 return method;
   1141             }
   1142         } catch (NoSuchMethodException nsm) {
   1143             // Ignored
   1144         }
   1145         return null;
   1146     }
   1147 
   1148     boolean hasMethodWriteReplace() {
   1149         return (methodWriteReplace != null);
   1150     }
   1151 
   1152     Method getMethodWriteReplace() {
   1153         return methodWriteReplace;
   1154     }
   1155 
   1156     boolean hasMethodReadResolve() {
   1157         return (methodReadResolve != null);
   1158     }
   1159 
   1160     Method getMethodReadResolve() {
   1161         return methodReadResolve;
   1162     }
   1163 
   1164     boolean hasMethodWriteObject() {
   1165         return (methodWriteObject != null);
   1166     }
   1167 
   1168     Method getMethodWriteObject() {
   1169         return methodWriteObject;
   1170     }
   1171 
   1172     boolean hasMethodReadObject() {
   1173         return (methodReadObject != null);
   1174     }
   1175 
   1176     Method getMethodReadObject() {
   1177         return methodReadObject;
   1178     }
   1179 
   1180     boolean hasMethodReadObjectNoData() {
   1181         return (methodReadObjectNoData != null);
   1182     }
   1183 
   1184     Method getMethodReadObjectNoData() {
   1185         return methodReadObjectNoData;
   1186     }
   1187 
   1188     void initPrivateFields(ObjectStreamClass desc) {
   1189         methodWriteReplace = desc.methodWriteReplace;
   1190         methodReadResolve = desc.methodReadResolve;
   1191         methodWriteObject = desc.methodWriteObject;
   1192         methodReadObject = desc.methodReadObject;
   1193         methodReadObjectNoData = desc.methodReadObjectNoData;
   1194     }
   1195 
   1196     /**
   1197      * Set the class (java.lang.Class) that the receiver represents
   1198      *
   1199      * @param c
   1200      *            aClass, the new class that the receiver describes
   1201      */
   1202     void setClass(Class<?> c) {
   1203         resolvedClass = c;
   1204     }
   1205 
   1206     /**
   1207      * Set the collection of field descriptors for the fields of the
   1208      * corresponding class
   1209      *
   1210      * @param f
   1211      *            ObjectStreamField[], the receiver's new collection of declared
   1212      *            fields for the class it represents
   1213      */
   1214     void setFields(ObjectStreamField[] f) {
   1215         fields = f;
   1216     }
   1217 
   1218     /**
   1219      * Set the collection of field descriptors for the input fields of the
   1220      * corresponding class
   1221      *
   1222      * @param f
   1223      *            ObjectStreamField[], the receiver's new collection of input
   1224      *            fields for the class it represents
   1225      */
   1226     void setLoadFields(ObjectStreamField[] f) {
   1227         loadFields = f;
   1228     }
   1229 
   1230     /**
   1231      * Set the flags for this descriptor, where possible combined values are
   1232      *
   1233      * ObjectStreamConstants.SC_WRITE_METHOD
   1234      * ObjectStreamConstants.SC_SERIALIZABLE
   1235      * ObjectStreamConstants.SC_EXTERNALIZABLE
   1236      *
   1237      * @param b
   1238      *            byte, the receiver's new flags for the class it represents
   1239      */
   1240     void setFlags(byte b) {
   1241         flags = b;
   1242     }
   1243 
   1244     /**
   1245      * Set the name of the class represented by the receiver
   1246      *
   1247      * @param newName
   1248      *            a String, the new fully qualified name of the class the
   1249      *            receiver represents
   1250      */
   1251     void setName(String newName) {
   1252         className = newName;
   1253     }
   1254 
   1255     /**
   1256      * Set the Serial Version User ID of the class represented by the receiver
   1257      *
   1258      * @param l
   1259      *            a long, the new SUID for the class represented by the receiver
   1260      */
   1261     void setSerialVersionUID(long l) {
   1262         svUID = l;
   1263     }
   1264 
   1265     /**
   1266      * Set the descriptor for the superclass of the class described by the
   1267      * receiver
   1268      *
   1269      * @param c
   1270      *            an ObjectStreamClass, the new ObjectStreamClass for the
   1271      *            superclass of the class represented by the receiver
   1272      */
   1273     void setSuperclass(ObjectStreamClass c) {
   1274         superclass = c;
   1275     }
   1276 
   1277     private int primitiveSize(Class<?> type) {
   1278         if (type == byte.class || type == boolean.class) {
   1279             return 1;
   1280         }
   1281         if (type == short.class || type == char.class) {
   1282             return 2;
   1283         }
   1284         if (type == int.class || type == float.class) {
   1285             return 4;
   1286         }
   1287         if (type == long.class || type == double.class) {
   1288             return 8;
   1289         }
   1290         throw new AssertionError();
   1291     }
   1292 
   1293     /**
   1294      * Returns a string containing a concise, human-readable description of this
   1295      * descriptor.
   1296      *
   1297      * @return a printable representation of this descriptor.
   1298      */
   1299     @Override
   1300     public String toString() {
   1301         return getName() + ": static final long serialVersionUID =" + getSerialVersionUID() + "L;";
   1302     }
   1303 }
   1304