• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setConstructor(long newConstructor)194     void setConstructor(long newConstructor) {
195         constructor = newConstructor;
196     }
197 
getConstructor()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      */
ObjectStreamClass()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      */
createClassDesc(Class<?> cl)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      */
buildFieldDescriptors(Field[] declaredFields)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      */
computeSerialVersionUID(Class<?> cl, Field[] fields)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      */
descriptorForFieldSignature(String signature)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      */
descriptorForSignature(String signature)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      */
fieldSerialPersistentFields(Class<?> cl)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      */
forClass()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      */
getConstructorSignature(Constructor<?> c)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      */
getField(String name)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      */
fields()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      */
getFields()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      */
copyFieldAttributes()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      */
getLoadFields()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      */
getFieldSignature(Field f)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      */
getFlags()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      */
getMethodSignature(Method m)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      */
getName()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      */
getSerialVersionUID()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      */
getSuperclass()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      */
hasClinit(Class<?> cl)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      */
isExternalizable(Class<?> cl)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      */
isPrimitiveType(char typecode)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      */
isSerializable(Class<?> cl)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      */
resolveProperties()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 
isSerializable()895     boolean isSerializable() {
896         resolveProperties();
897         return isSerializable;
898     }
899 
isExternalizable()900     boolean isExternalizable() {
901         resolveProperties();
902         return isExternalizable;
903     }
904 
isProxy()905     boolean isProxy() {
906         resolveProperties();
907         return isProxy;
908     }
909 
isEnum()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      */
littleEndianLongAt(byte[] buffer, int position)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      */
lookup(Class<?> cl)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      */
lookupAny(Class<?> cl)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      */
lookupStreamClass(Class<?> cl)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      */
findMethod(Class<?> cl, String methodName)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      */
findPrivateMethod(Class<?> cl, String methodName, Class<?>[] param)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 
hasMethodWriteReplace()1042     boolean hasMethodWriteReplace() {
1043         return (methodWriteReplace != null);
1044     }
1045 
getMethodWriteReplace()1046     Method getMethodWriteReplace() {
1047         return methodWriteReplace;
1048     }
1049 
hasMethodReadResolve()1050     boolean hasMethodReadResolve() {
1051         return (methodReadResolve != null);
1052     }
1053 
getMethodReadResolve()1054     Method getMethodReadResolve() {
1055         return methodReadResolve;
1056     }
1057 
hasMethodWriteObject()1058     boolean hasMethodWriteObject() {
1059         return (methodWriteObject != null);
1060     }
1061 
getMethodWriteObject()1062     Method getMethodWriteObject() {
1063         return methodWriteObject;
1064     }
1065 
hasMethodReadObject()1066     boolean hasMethodReadObject() {
1067         return (methodReadObject != null);
1068     }
1069 
getMethodReadObject()1070     Method getMethodReadObject() {
1071         return methodReadObject;
1072     }
1073 
hasMethodReadObjectNoData()1074     boolean hasMethodReadObjectNoData() {
1075         return (methodReadObjectNoData != null);
1076     }
1077 
getMethodReadObjectNoData()1078     Method getMethodReadObjectNoData() {
1079         return methodReadObjectNoData;
1080     }
1081 
initPrivateFields(ObjectStreamClass desc)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      */
setClass(Class<?> c)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      */
setFields(ObjectStreamField[] f)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      */
setLoadFields(ObjectStreamField[] f)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      */
setFlags(byte b)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      */
setName(String newName)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      */
setSerialVersionUID(long l)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      */
setSuperclass(ObjectStreamClass c)1167     void setSuperclass(ObjectStreamClass c) {
1168         superclass = c;
1169     }
1170 
primitiveSize(Class<?> type)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
toString()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