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