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