KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > corba > se > impl > io > ObjectStreamClass


1 /*
2  * @(#)ObjectStreamClass.java 1.56 05/09/13
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 /*
8  * Licensed Materials - Property of IBM
9  * RMI-IIOP v1.0
10  * Copyright IBM Corp. 1998 1999 All Rights Reserved
11  *
12  * US Government Users Restricted Rights - Use, duplication or
13  * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
14  */

15
16 package com.sun.corba.se.impl.io;
17
18 import java.security.MessageDigest JavaDoc;
19 import java.security.NoSuchAlgorithmException JavaDoc;
20 import java.security.DigestOutputStream JavaDoc;
21 import java.security.AccessController JavaDoc;
22 import java.security.PrivilegedExceptionAction JavaDoc;
23 import java.security.PrivilegedActionException JavaDoc;
24 import java.security.PrivilegedAction JavaDoc;
25
26 import java.lang.reflect.Modifier JavaDoc;
27 import java.lang.reflect.Array JavaDoc;
28 import java.lang.reflect.Field JavaDoc;
29 import java.lang.reflect.Member JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31 import java.lang.reflect.Constructor JavaDoc;
32 import java.lang.reflect.Proxy JavaDoc;
33 import java.lang.reflect.InvocationTargetException JavaDoc;
34
35 import java.io.IOException JavaDoc;
36 import java.io.DataOutputStream JavaDoc;
37 import java.io.ByteArrayOutputStream JavaDoc;
38 import java.io.InvalidClassException JavaDoc;
39 import java.io.Serializable JavaDoc;
40
41 import java.util.Arrays JavaDoc;
42 import java.util.Comparator JavaDoc;
43 import java.util.Hashtable JavaDoc;
44
45 import com.sun.corba.se.impl.util.RepositoryId;
46
47 import sun.misc.SoftCache;
48
49 import org.omg.CORBA.ValueMember JavaDoc;
50
51 import sun.corba.Bridge;
52
53 /**
54  * A ObjectStreamClass describes a class that can be serialized to a stream
55  * or a class that was serialized to a stream. It contains the name
56  * and the serialVersionUID of the class.
57  * <br>
58  * The ObjectStreamClass for a specific class loaded in this Java VM can
59  * be found using the lookup method.
60  *
61  * @author Roger Riggs
62  * @(#)ObjectStreamClass.java 1.17 99/06/07
63  * @since JDK1.1
64  */

65 public class ObjectStreamClass implements java.io.Serializable JavaDoc {
66     private static final boolean DEBUG_SVUID = false ;
67
68     public static final long kDefaultUID = -1;
69
70     private static Object JavaDoc noArgsList[] = {};
71     private static Class JavaDoc noTypesList[] = {};
72     
73     private static Hashtable JavaDoc translatedFields;
74
75     private static final Bridge bridge =
76     (Bridge)AccessController.doPrivileged(
77         new PrivilegedAction JavaDoc() {
78         public Object JavaDoc run() {
79             return Bridge.get() ;
80         }
81         }
82     ) ;
83
84     /** Find the descriptor for a class that can be serialized. Null
85      * is returned if the specified class does not implement
86      * java.io.Serializable or java.io.Externalizable.
87      */

88     static final ObjectStreamClass lookup(Class JavaDoc cl)
89     {
90     ObjectStreamClass desc = lookupInternal(cl);
91     if (desc.isSerializable() || desc.isExternalizable())
92         return desc;
93     return null;
94     }
95
96     /*
97      * Find the class descriptor for the specified class.
98      * Package access only so it can be called from ObjectIn/OutStream.
99      */

100     static ObjectStreamClass lookupInternal(Class JavaDoc cl)
101     {
102     /* Synchronize on the hashtable so no two threads will do
103      * this at the same time.
104      */

105     ObjectStreamClass desc = null;
106     synchronized (descriptorFor) {
107         /* Find the matching descriptor if it already known */
108             desc = (ObjectStreamClass)descriptorFor.get(cl);
109         if (desc == null) {
110                 /* Check if it's serializable */
111                 boolean serializable = classSerializable.isAssignableFrom(cl);
112
113                 /* If the class is only Serializable,
114                  * lookup the descriptor for the superclass.
115                  */

116                 ObjectStreamClass superdesc = null;
117                 if (serializable) {
118                     Class JavaDoc superclass = cl.getSuperclass();
119                     if (superclass != null)
120                         superdesc = lookup(superclass);
121                 }
122
123                 /* Check if its' externalizable.
124                  * If it's Externalizable, clear the serializable flag.
125                  * Only one or the other may be set in the protocol.
126                  */

127                 boolean externalizable = false;
128                 if (serializable) {
129                     externalizable =
130                         ((superdesc != null) && superdesc.isExternalizable()) ||
131                         classExternalizable.isAssignableFrom(cl);
132                     if (externalizable) {
133                         serializable = false;
134                     }
135                 }
136
137                 /* Create a new version descriptor,
138                  * it put itself in the known table.
139                  */

140                 desc = new ObjectStreamClass(cl, superdesc,
141                                              serializable, externalizable);
142             }
143
144             // Must always call init. See bug 4488137. This code was
145
// incorrectly changed to return immediately on a non-null
146
// cache result. That allowed threads to gain access to
147
// unintialized instances.
148
//
149
// History: Note, the following init() call was originally within
150
// the synchronization block, as it currently is now. Later, the
151
// init() call was moved outside the synchronization block, and
152
// the init() method used a private member variable lock, to
153
// avoid performance problems. See bug 4165204. But that lead to
154
// a deadlock situation, see bug 5104239. Hence, the init() method
155
// has now been moved back into the synchronization block. The
156
// right approach to solving these problems would be to rewrite
157
// this class, based on the latest java.io.ObjectStreamClass.
158
desc.init();
159         }
160
161     return desc;
162     }
163
164     /**
165      * The name of the class described by this descriptor.
166      */

167     public final String JavaDoc getName() {
168     return name;
169     }
170
171     /**
172      * Return the serialVersionUID for this class.
173      * The serialVersionUID defines a set of classes all with the same name
174      * that have evolved from a common root class and agree to be serialized
175      * and deserialized using a common format.
176      */

177     public static final long getSerialVersionUID( java.lang.Class JavaDoc clazz) {
178     ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
179         if( theosc != null )
180     {
181         return theosc.getSerialVersionUID( );
182     }
183     return 0;
184     }
185
186     /**
187      * Return the serialVersionUID for this class.
188      * The serialVersionUID defines a set of classes all with the same name
189      * that have evolved from a common root class and agree to be serialized
190      * and deserialized using a common format.
191      */

192     public final long getSerialVersionUID() {
193     return suid;
194     }
195
196     /**
197      * Return the serialVersionUID string for this class.
198      * The serialVersionUID defines a set of classes all with the same name
199      * that have evolved from a common root class and agree to be serialized
200      * and deserialized using a common format.
201      */

202     public final String JavaDoc getSerialVersionUIDStr() {
203     if (suidStr == null)
204         suidStr = Long.toHexString(suid).toUpperCase();
205     return suidStr;
206     }
207
208     /**
209      * Return the actual (computed) serialVersionUID for this class.
210      */

211     public static final long getActualSerialVersionUID( java.lang.Class JavaDoc clazz )
212     {
213     ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
214     if( theosc != null )
215     {
216         return theosc.getActualSerialVersionUID( );
217     }
218     return 0;
219     }
220
221     /**
222      * Return the actual (computed) serialVersionUID for this class.
223      */

224     public final long getActualSerialVersionUID() {
225     return actualSuid;
226     }
227
228     /**
229      * Return the actual (computed) serialVersionUID for this class.
230      */

231     public final String JavaDoc getActualSerialVersionUIDStr() {
232     if (actualSuidStr == null)
233         actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
234     return actualSuidStr;
235     }
236
237     /**
238      * Return the class in the local VM that this version is mapped to.
239      * Null is returned if there is no corresponding local class.
240      */

241     public final Class JavaDoc forClass() {
242     return ofClass;
243     }
244
245     /**
246      * Return an array of the fields of this serializable class.
247      * @return an array containing an element for each persistent
248      * field of this class. Returns an array of length zero if
249      * there are no fields.
250      * @since JDK1.2
251      */

252     public ObjectStreamField[] getFields() {
253         // Return a copy so the caller can't change the fields.
254
if (fields.length > 0) {
255         ObjectStreamField[] dup = new ObjectStreamField[fields.length];
256         System.arraycopy(fields, 0, dup, 0, fields.length);
257         return dup;
258     } else {
259         return fields;
260     }
261     }
262
263     public boolean hasField(ValueMember JavaDoc field)
264     {
265     try {
266         for (int i = 0; i < fields.length; i++) {
267         if (fields[i].getName().equals(field.name)) {
268             if (fields[i].getSignature().equals(
269             ValueUtility.getSignature(field)))
270             return true;
271         }
272         }
273     } catch (Exception JavaDoc exc) {
274         // Ignore this; all we want to do is return false
275
// Note that ValueUtility.getSignature can throw checked exceptions.
276
}
277
278     return false;
279     }
280
281     /* Avoid unnecessary allocations. */
282     final ObjectStreamField[] getFieldsNoCopy() {
283     return fields;
284     }
285
286     /**
287      * Get the field of this class by name.
288      * @return The ObjectStreamField object of the named field or null if there
289      * is no such named field.
290      */

291     public final ObjectStreamField getField(String JavaDoc name) {
292         /* Binary search of fields by name.
293      */

294         for (int i = fields.length-1; i >= 0; i--) {
295             if (name.equals(fields[i].getName())) {
296                 return fields[i];
297         }
298         }
299     return null;
300     }
301
302     public Serializable JavaDoc writeReplace(Serializable JavaDoc value) {
303     if (writeReplaceObjectMethod != null) {
304         try {
305         return (Serializable JavaDoc) writeReplaceObjectMethod.invoke(value,noArgsList);
306         } catch(Throwable JavaDoc t) {
307         throw new RuntimeException JavaDoc(t);
308         }
309     }
310     else return value;
311     }
312
313     public Object JavaDoc readResolve(Object JavaDoc value) {
314     if (readResolveObjectMethod != null) {
315         try {
316         return readResolveObjectMethod.invoke(value,noArgsList);
317         } catch(Throwable JavaDoc t) {
318         throw new RuntimeException JavaDoc(t);
319         }
320     }
321     else return value;
322     }
323
324     /**
325      * Return a string describing this ObjectStreamClass.
326      */

327     public final String JavaDoc toString() {
328     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
329
330     sb.append(name);
331     sb.append(": static final long serialVersionUID = ");
332     sb.append(Long.toString(suid));
333     sb.append("L;");
334     return sb.toString();
335     }
336
337     /*
338      * Create a new ObjectStreamClass from a loaded class.
339      * Don't call this directly, call lookup instead.
340      */

341     private ObjectStreamClass(java.lang.Class JavaDoc cl, ObjectStreamClass superdesc,
342                   boolean serial, boolean extern)
343     {
344     ofClass = cl; /* created from this class */
345
346         if (Proxy.isProxyClass(cl)) {
347             forProxyClass = true;
348         }
349
350     name = cl.getName();
351     superclass = superdesc;
352     serializable = serial;
353         if (!forProxyClass) {
354             // proxy classes are never externalizable
355
externalizable = extern;
356         }
357
358     /*
359      * Enter this class in the table of known descriptors.
360      * Otherwise, when the fields are read it may recurse
361      * trying to find the descriptor for itself.
362      */

363         descriptorFor.put(cl, this);
364
365         /*
366          * The remainder of initialization occurs in init(), which is called
367          * after the lock on the global class descriptor table has been
368          * released.
369          */

370     }
371
372     /*
373      * Initialize class descriptor. This method is only invoked on class
374      * descriptors created via calls to lookupInternal(). This method is kept
375      * separate from the ObjectStreamClass constructor so that lookupInternal
376      * does not have to hold onto a global class descriptor table lock while the
377      * class descriptor is being initialized (see bug 4165204).
378      */

379
380
381     private void init() {
382       synchronized (lock) {
383
384         // See description at definition of initialized.
385
if (initialized)
386             return;
387
388     final Class JavaDoc cl = ofClass;
389
390     if (!serializable ||
391         externalizable ||
392         forProxyClass ||
393         name.equals("java.lang.String")) {
394         fields = NO_FIELDS;
395     } else if (serializable) {
396             /* Ask for permission to override field access checks.
397              */

398             AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
399                 public Object JavaDoc run() {
400         /* Fill in the list of persistent fields.
401          * If it is declared, use the declared serialPersistentFields.
402          * Otherwise, extract the fields from the class itself.
403          */

404         try {
405                     Field JavaDoc pf = cl.getDeclaredField("serialPersistentFields");
406                 // serial bug 7; the serialPersistentFields were not
407
// being read and stored as Accessible bit was not set
408
pf.setAccessible(true);
409                 // serial bug 7; need to find if the field is of type
410
// java.io.ObjectStreamField
411
java.io.ObjectStreamField JavaDoc[] f =
412                            (java.io.ObjectStreamField JavaDoc[])pf.get(cl);
413             int mods = pf.getModifiers();
414             if ((Modifier.isPrivate(mods)) &&
415             (Modifier.isStatic(mods)) &&
416             (Modifier.isFinal(mods)))
417                 {
418             fields = (ObjectStreamField[])translateFields((Object JavaDoc[])pf.get(cl));
419             }
420         } catch (NoSuchFieldException JavaDoc e) {
421             fields = null;
422         } catch (IllegalAccessException JavaDoc e) {
423             fields = null;
424         } catch (IllegalArgumentException JavaDoc e) {
425             fields = null;
426                 } catch (ClassCastException JavaDoc e) {
427                     /* Thrown if a field serialPersistentField exists
428                      * but it is not of type ObjectStreamField.
429                      */

430                     fields = null;
431                 }
432
433
434         if (fields == null) {
435             /* Get all of the declared fields for this
436              * Class. setAccessible on all fields so they
437              * can be accessed later. Create a temporary
438              * ObjectStreamField array to hold each
439              * non-static, non-transient field. Then copy the
440              * temporary array into an array of the correct
441              * size once the number of fields is known.
442              */

443                     Field JavaDoc[] actualfields = cl.getDeclaredFields();
444
445             int numFields = 0;
446             ObjectStreamField[] tempFields =
447             new ObjectStreamField[actualfields.length];
448             for (int i = 0; i < actualfields.length; i++) {
449             Field JavaDoc fld = actualfields[i] ;
450             int modifiers = fld.getModifiers();
451             if (!Modifier.isStatic(modifiers) &&
452                 !Modifier.isTransient(modifiers)) {
453                 fld.setAccessible(true) ;
454                 tempFields[numFields++] = new ObjectStreamField(fld);
455             }
456             }
457
458             fields = new ObjectStreamField[numFields];
459             System.arraycopy(tempFields, 0, fields, 0, numFields);
460
461         } else {
462             // For each declared persistent field, look for an actual
463
// reflected Field. If there is one, make sure it's the correct
464
// type and cache it in the ObjectStreamClass for that field.
465
for (int j = fields.length-1; j >= 0; j--) {
466             try {
467                             Field JavaDoc reflField = cl.getDeclaredField(fields[j].getName());
468                 if (fields[j].getType() == reflField.getType()) {
469                 reflField.setAccessible(true);
470                 fields[j].setField(reflField);
471                 }
472             } catch (NoSuchFieldException JavaDoc e) {
473                 // Nothing to do
474
}
475             }
476         }
477             return null;
478         }
479         });
480
481         if (fields.length > 1)
482         Arrays.sort(fields);
483
484         /* Set up field data for use while writing using the API api. */
485         computeFieldInfo();
486     }
487
488         /* Get the serialVersionUID from the class.
489          * It uses the access override mechanism so make sure
490          * the field objects is only used here.
491          *
492          * NonSerializable classes have a serialVerisonUID of 0L.
493          */

494          if (isNonSerializable()) {
495              suid = 0L;
496          } else {
497              // Lookup special Serializable members using reflection.
498
AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
499                 public Object JavaDoc run() {
500                 if (forProxyClass) {
501                     // proxy classes always have serialVersionUID of 0L
502
suid = 0L;
503                 } else {
504                 try {
505                         final Field JavaDoc f = cl.getDeclaredField("serialVersionUID");
506                     int mods = f.getModifiers();
507             // SerialBug 5: static final SUID should be read
508
if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) {
509                             f.setAccessible(true);
510                     suid = f.getLong(cl);
511                 // SerialBug 2: should be computed after writeObject
512
// actualSuid = computeStructuralUID(cl);
513
} else {
514                     suid = _computeSerialVersionUID(cl);
515                         // SerialBug 2: should be computed after writeObject
516
// actualSuid = computeStructuralUID(cl);
517
}
518                 } catch (NoSuchFieldException JavaDoc ex) {
519                     suid = _computeSerialVersionUID(cl);
520                     // SerialBug 2: should be computed after writeObject
521
// actualSuid = computeStructuralUID(cl);
522
} catch (IllegalAccessException JavaDoc ex) {
523                         suid = _computeSerialVersionUID(cl);
524                     }
525             }
526
527                 writeReplaceObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
528             "writeReplace", noTypesList, Object JavaDoc.class);
529
530                 readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
531             "readResolve", noTypesList, Object JavaDoc.class);
532     
533         if (externalizable)
534             cons = getExternalizableConstructor(cl) ;
535         else
536             cons = getSerializableConstructor(cl) ;
537
538                 if (serializable && !forProxyClass) {
539                 /* Look for the writeObject method
540                  * Set the accessible flag on it here. ObjectOutputStream
541                  * will call it as necessary.
542                  */

543             writeObjectMethod = getPrivateMethod( cl, "writeObject",
544             new Class JavaDoc[] { java.io.ObjectOutputStream JavaDoc.class }, Void.TYPE ) ;
545             readObjectMethod = getPrivateMethod( cl, "readObject",
546             new Class JavaDoc[] { java.io.ObjectInputStream JavaDoc.class }, Void.TYPE ) ;
547             }
548             return null;
549         }
550       });
551     }
552
553         // This call depends on a lot of information computed above!
554
actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);
555
556         // If we have a write object method, precompute the
557
// RMI-IIOP stream format version 2 optional data
558
// repository ID.
559
if (hasWriteObject())
560             rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId();
561
562         // This must be done last.
563
initialized = true;
564       }
565     }
566
567     /**
568      * Returns non-static private method with given signature defined by given
569      * class, or null if none found. Access checks are disabled on the
570      * returned method (if any).
571      */

572     private static Method JavaDoc getPrivateMethod(Class JavaDoc cl, String JavaDoc name,
573                        Class JavaDoc[] argTypes,
574                        Class JavaDoc returnType)
575     {
576     try {
577         Method JavaDoc meth = cl.getDeclaredMethod(name, argTypes);
578         meth.setAccessible(true);
579         int mods = meth.getModifiers();
580         return ((meth.getReturnType() == returnType) &&
581             ((mods & Modifier.STATIC) == 0) &&
582             ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
583     } catch (NoSuchMethodException JavaDoc ex) {
584         return null;
585     }
586     }
587
588     // Specific to RMI-IIOP
589
/**
590      * Java to IDL ptc-02-01-12 1.5.1
591      *
592      * "The rep_id string passed to the start_value method must be
593      * 'RMI:org.omg.custom.class:hashcode:suid' where class is the
594      * fully-qualified name of the class whose writeObject method
595      * is being invoked and hashcode and suid are the class's hashcode
596      * and SUID."
597      */

598     private String JavaDoc computeRMIIIOPOptionalDataRepId() {
599
600         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc("RMI:org.omg.custom.");
601         sbuf.append(RepositoryId.convertToISOLatin1(this.getName()));
602         sbuf.append(':');
603         sbuf.append(this.getActualSerialVersionUIDStr());
604         sbuf.append(':');
605         sbuf.append(this.getSerialVersionUIDStr());
606
607         return sbuf.toString();
608     }
609
610     /**
611      * This will return null if there is no writeObject method.
612      */

613     public final String JavaDoc getRMIIIOPOptionalDataRepId() {
614         return rmiiiopOptionalDataRepId;
615     }
616
617     /*
618      * Create an empty ObjectStreamClass for a class about to be read.
619      * This is separate from read so ObjectInputStream can assign the
620      * wire handle early, before any nested ObjectStreamClass might
621      * be read.
622      */

623     ObjectStreamClass(String JavaDoc n, long s) {
624     name = n;
625     suid = s;
626     superclass = null;
627     }
628
629     private static Object JavaDoc[] translateFields(Object JavaDoc objs[])
630         throws NoSuchFieldException JavaDoc {
631         try{
632             java.io.ObjectStreamField JavaDoc fields[] = (java.io.ObjectStreamField JavaDoc[])objs;
633             Object JavaDoc translation[] = null;
634                        
635             if (translatedFields == null)
636                 translatedFields = new Hashtable JavaDoc();
637                        
638             translation = (Object JavaDoc[])translatedFields.get(fields);
639                        
640             if (translation != null)
641                 return translation;
642             else {
643                 Class JavaDoc osfClass = Class.forName("com.sun.corba.se.impl.io.ObjectStreamField");
644                 translation = (Object JavaDoc[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
645                 Object JavaDoc arg[] = new Object JavaDoc[2];
646                 Class JavaDoc types[] = {String JavaDoc.class, Class JavaDoc.class};
647                 Constructor JavaDoc constructor = osfClass.getDeclaredConstructor(types);
648                 for (int i = fields.length -1; i >= 0; i--){
649                     arg[0] = fields[i].getName();
650                     arg[1] = fields[i].getType();
651                        
652                     translation[i] = constructor.newInstance(arg);
653                 }
654                 translatedFields.put(fields, translation);
655                        
656             }
657
658             return (Object JavaDoc[])translation;
659         }
660         catch(Throwable JavaDoc t){
661             NoSuchFieldException JavaDoc nsfe = new NoSuchFieldException JavaDoc();
662         nsfe.initCause( t ) ;
663         throw nsfe ;
664         }
665     }
666
667     /*
668      * Set the class this version descriptor matches.
669      * The base class name and serializable hash must match.
670      * Fill in the reflected Fields that will be used
671      * for reading.
672      */

673     final void setClass(Class JavaDoc cl) throws InvalidClassException JavaDoc {
674
675     if (cl == null) {
676         localClassDesc = null;
677         ofClass = null;
678         computeFieldInfo();
679         return;
680     }
681
682     localClassDesc = lookupInternal(cl);
683     if (localClassDesc == null)
684         // XXX I18N, logging needed
685
throw new InvalidClassException JavaDoc(cl.getName(),
686                         "Local class not compatible");
687     if (suid != localClassDesc.suid) {
688
689             /* Check for exceptional cases that allow mismatched suid. */
690
691             /* Allow adding Serializable or Externalizable
692              * to a later release of the class.
693              */

694             boolean addedSerialOrExtern =
695                 isNonSerializable() || localClassDesc.isNonSerializable();
696
697         /* Disregard the serialVersionUID of an array
698          * when name and cl.Name differ. If resolveClass() returns
699          * an array with a different package name,
700          * the serialVersionUIDs will not match since the fully
701          * qualified array class is used in the
702          * computation of the array's serialVersionUID. There is
703          * no way to set a permanent serialVersionUID for an array type.
704          */

705
706             boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));
707
708             if (! arraySUID && ! addedSerialOrExtern ) {
709         // XXX I18N, logging needed
710
throw new InvalidClassException JavaDoc(cl.getName(),
711                         "Local class not compatible:" +
712                         " stream classdesc serialVersionUID=" + suid +
713                         " local class serialVersionUID=" + localClassDesc.suid);
714         }
715         }
716
717     /* compare the class names, stripping off package names. */
718     if (! compareClassNames(name, cl.getName(), '.'))
719         // XXX I18N, logging needed
720
throw new InvalidClassException JavaDoc(cl.getName(),
721                          "Incompatible local class name. " +
722                          "Expected class name compatible with " +
723                          name);
724
725     /*
726      * Test that both implement either serializable or externalizable.
727      */

728
729     // The next check is more generic, since it covers the
730
// Proxy case, the JDK 1.3 serialization code has
731
// both checks
732
//if ((serializable && localClassDesc.externalizable) ||
733
// (externalizable && localClassDesc.serializable))
734
// throw new InvalidClassException(localCl.getName(),
735
// "Serializable is incompatible with Externalizable");
736

737         if ((serializable != localClassDesc.serializable) ||
738             (externalizable != localClassDesc.externalizable) ||
739         (!serializable && !externalizable))
740
741         // XXX I18N, logging needed
742
throw new InvalidClassException JavaDoc(cl.getName(),
743                         "Serialization incompatible with Externalization");
744
745     /* Set up the reflected Fields in the class where the value of each
746      * field in this descriptor should be stored.
747      * Each field in this ObjectStreamClass (the source) is located (by
748      * name) in the ObjectStreamClass of the class(the destination).
749      * In the usual (non-versioned case) the field is in both
750      * descriptors and the types match, so the reflected Field is copied.
751      * If the type does not match, a InvalidClass exception is thrown.
752      * If the field is not present in the class, the reflected Field
753      * remains null so the field will be read but discarded.
754      * If extra fields are present in the class they are ignored. Their
755      * values will be set to the default value by the object allocator.
756      * Both the src and dest field list are sorted by type and name.
757      */

758
759     ObjectStreamField[] destfield =
760         (ObjectStreamField[])localClassDesc.fields;
761     ObjectStreamField[] srcfield =
762         (ObjectStreamField[])fields;
763
764     int j = 0;
765     nextsrc:
766     for (int i = 0; i < srcfield.length; i++ ) {
767         /* Find this field in the dest*/
768         for (int k = j; k < destfield.length; k++) {
769         if (srcfield[i].getName().equals(destfield[k].getName())) {
770             /* found match */
771             if (srcfield[i].isPrimitive() &&
772             !srcfield[i].typeEquals(destfield[k])) {
773             // XXX I18N, logging needed
774
throw new InvalidClassException JavaDoc(cl.getName(),
775                             "The type of field " +
776                             srcfield[i].getName() +
777                             " of class " + name +
778                             " is incompatible.");
779             }
780
781             /* Skip over any fields in the dest that are not in the src */
782             j = k;
783
784             srcfield[i].setField(destfield[j].getField());
785             // go on to the next source field
786
continue nextsrc;
787         }
788         }
789     }
790
791     /* Set up field data for use while reading from the input stream. */
792     computeFieldInfo();
793
794     /* Remember the class this represents */
795     ofClass = cl;
796
797         /* get the cache of these methods from the local class
798          * implementation.
799          */

800         readObjectMethod = localClassDesc.readObjectMethod;
801         readResolveObjectMethod = localClassDesc.readResolveObjectMethod;
802     }
803
804     /* Compare the base class names of streamName and localName.
805      *
806      * @return Return true iff the base class name compare.
807      * @parameter streamName Fully qualified class name.
808      * @parameter localName Fully qualified class name.
809      * @parameter pkgSeparator class names use either '.' or '/'.
810      *
811      * Only compare base class name to allow package renaming.
812      */

813     static boolean compareClassNames(String JavaDoc streamName,
814                      String JavaDoc localName,
815                      char pkgSeparator) {
816     /* compare the class names, stripping off package names. */
817     int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
818     if (streamNameIndex < 0)
819         streamNameIndex = 0;
820
821     int localNameIndex = localName.lastIndexOf(pkgSeparator);
822     if (localNameIndex < 0)
823         localNameIndex = 0;
824
825     return streamName.regionMatches(false, streamNameIndex,
826                     localName, localNameIndex,
827                     streamName.length() - streamNameIndex);
828     }
829
830     /*
831      * Compare the types of two class descriptors.
832      * They match if they have the same class name and suid
833      */

834     final boolean typeEquals(ObjectStreamClass other) {
835     return (suid == other.suid) &&
836         compareClassNames(name, other.name, '.');
837     }
838
839     /*
840      * Return the superclass descriptor of this descriptor.
841      */

842     final void setSuperclass(ObjectStreamClass s) {
843     superclass = s;
844     }
845
846     /*
847      * Return the superclass descriptor of this descriptor.
848      */

849     final ObjectStreamClass getSuperclass() {
850     return superclass;
851     }
852
853     /**
854      * Return whether the class has a readObject method
855      */

856     final boolean hasReadObject() {
857         return readObjectMethod != null;
858     }
859
860     /*
861      * Return whether the class has a writeObject method
862      */

863     final boolean hasWriteObject() {
864     return writeObjectMethod != null ;
865     }
866
867     /**
868      * Returns when or not this class should be custom
869      * marshaled (use chunking). This should happen if
870      * it is Externalizable OR if it or
871      * any of its superclasses has a writeObject method,
872      */

873     final boolean isCustomMarshaled() {
874     return (hasWriteObject() || isExternalizable())
875             || (superclass != null && superclass.isCustomMarshaled());
876     }
877
878     /*
879      * Return true if all instances of 'this' Externalizable class
880      * are written in block-data mode from the stream that 'this' was read
881      * from. <p>
882      *
883      * In JDK 1.1, all Externalizable instances are not written
884      * in block-data mode.
885      * In JDK 1.2, all Externalizable instances, by default, are written
886      * in block-data mode and the Externalizable instance is terminated with
887      * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
888      * instances.
889      *
890      * IMPLEMENTATION NOTE:
891      * This should have been a mode maintained per stream; however,
892      * for compatibility reasons, it was only possible to record
893      * this change per class. All Externalizable classes within
894      * a given stream should either have this mode enabled or
895      * disabled. This is enforced by not allowing the PROTOCOL_VERSION
896      * of a stream to he changed after any objects have been written.
897      *
898      * @see ObjectOutputStream#useProtocolVersion
899      * @see ObjectStreamConstants#PROTOCOL_VERSION_1
900      * @see ObjectStreamConstants#PROTOCOL_VERSION_2
901      *
902      * @since JDK 1.2
903      */

904     boolean hasExternalizableBlockDataMode() {
905     return hasExternalizableBlockData;
906     }
907
908     /**
909      * Creates a new instance of the represented class. If the class is
910      * externalizable, invokes its public no-arg constructor; otherwise, if the
911      * class is serializable, invokes the no-arg constructor of the first
912      * non-serializable superclass. Throws UnsupportedOperationException if
913      * this class descriptor is not associated with a class, if the associated
914      * class is non-serializable or if the appropriate no-arg constructor is
915      * inaccessible/unavailable.
916      */

917     Object JavaDoc newInstance()
918     throws InstantiationException JavaDoc, InvocationTargetException JavaDoc,
919            UnsupportedOperationException JavaDoc
920     {
921     if (cons != null) {
922         try {
923         return cons.newInstance(new Object JavaDoc[0]);
924         } catch (IllegalAccessException JavaDoc ex) {
925         // should not occur, as access checks have been suppressed
926
InternalError JavaDoc ie = new InternalError JavaDoc();
927         ie.initCause( ex ) ;
928         throw ie ;
929         }
930     } else {
931         throw new UnsupportedOperationException JavaDoc();
932     }
933     }
934     
935     /**
936      * Returns public no-arg constructor of given class, or null if none found.
937      * Access checks are disabled on the returned constructor (if any), since
938      * the defining class may still be non-public.
939      */

940     private static Constructor JavaDoc getExternalizableConstructor(Class JavaDoc cl) {
941     try {
942         Constructor JavaDoc cons = cl.getDeclaredConstructor(new Class JavaDoc[0]);
943         cons.setAccessible(true);
944         return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
945         cons : null;
946     } catch (NoSuchMethodException JavaDoc ex) {
947         return null;
948     }
949     }
950
951     /**
952      * Returns subclass-accessible no-arg constructor of first non-serializable
953      * superclass, or null if none found. Access checks are disabled on the
954      * returned constructor (if any).
955      */

956     private static Constructor JavaDoc getSerializableConstructor(Class JavaDoc cl) {
957     Class JavaDoc initCl = cl;
958     while (Serializable JavaDoc.class.isAssignableFrom(initCl)) {
959         if ((initCl = initCl.getSuperclass()) == null) {
960         return null;
961         }
962     }
963     try {
964         Constructor JavaDoc cons = initCl.getDeclaredConstructor(new Class JavaDoc[0]);
965         int mods = cons.getModifiers();
966         if ((mods & Modifier.PRIVATE) != 0 ||
967         ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
968          !packageEquals(cl, initCl)))
969         {
970         return null;
971         }
972         cons = bridge.newConstructorForSerialization(cl, cons);
973         cons.setAccessible(true);
974         return cons;
975     } catch (NoSuchMethodException JavaDoc ex) {
976         return null;
977     }
978     }
979
980     /*
981      * Return the ObjectStreamClass of the local class this one is based on.
982      */

983     final ObjectStreamClass localClassDescriptor() {
984     return localClassDesc;
985     }
986
987     /*
988      * Get the Serializability of the class.
989      */

990     boolean isSerializable() {
991     return serializable;
992     }
993
994     /*
995      * Get the externalizability of the class.
996      */

997     boolean isExternalizable() {
998     return externalizable;
999     }
1000
1001    boolean isNonSerializable() {
1002        return ! (externalizable || serializable);
1003    }
1004
1005    /*
1006     * Calculate the size of the array needed to store primitive data and the
1007     * number of object references to read when reading from the input
1008     * stream.
1009     */

1010    private void computeFieldInfo() {
1011    primBytes = 0;
1012    objFields = 0;
1013
1014    for (int i = 0; i < fields.length; i++ ) {
1015        switch (fields[i].getTypeCode()) {
1016        case 'B':
1017        case 'Z':
1018            primBytes += 1;
1019            break;
1020        case 'C':
1021        case 'S':
1022            primBytes += 2;
1023            break;
1024
1025        case 'I':
1026        case 'F':
1027            primBytes += 4;
1028            break;
1029        case 'J':
1030        case 'D' :
1031            primBytes += 8;
1032            break;
1033
1034        case 'L':
1035        case '[':
1036            objFields += 1;
1037            break;
1038        }
1039    }
1040    }
1041
1042    private static void msg( String JavaDoc str )
1043    {
1044    System.out.println( str ) ;
1045    }
1046
1047    /* JDK 1.5 has introduced some new modifier bits (such as SYNTHETIC)
1048     * that can affect the SVUID computation (see bug 4897937). These bits
1049     * must be ignored, as otherwise interoperability with ORBs in earlier
1050     * JDK versions can be compromised. I am adding these masks for this
1051     * purpose as discussed in the CCC for this bug (see http://ccc.sfbay/4897937).
1052     */

1053
1054    public static final int CLASS_MASK = Modifier.PUBLIC | Modifier.FINAL |
1055    Modifier.INTERFACE | Modifier.ABSTRACT ;
1056    public static final int FIELD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
1057    Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
1058    Modifier.TRANSIENT | Modifier.VOLATILE ;
1059    public static final int METHOD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
1060    Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
1061    Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT |
1062    Modifier.STRICT ;
1063    
1064    /*
1065     * Compute a hash for the specified class. Incrementally add
1066     * items to the hash accumulating in the digest stream.
1067     * Fold the hash into a long. Use the SHA secure hash function.
1068     */

1069    private static long _computeSerialVersionUID(Class JavaDoc cl) {
1070    if (DEBUG_SVUID)
1071        msg( "Computing SerialVersionUID for " + cl ) ;
1072    ByteArrayOutputStream JavaDoc devnull = new ByteArrayOutputStream JavaDoc(512);
1073
1074    long h = 0;
1075    try {
1076        MessageDigest JavaDoc md = MessageDigest.getInstance("SHA");
1077        DigestOutputStream JavaDoc mdo = new DigestOutputStream JavaDoc(devnull, md);
1078        DataOutputStream JavaDoc data = new DataOutputStream JavaDoc(mdo);
1079
1080        if (DEBUG_SVUID)
1081        msg( "\twriteUTF( \"" + cl.getName() + "\" )" ) ;
1082        data.writeUTF(cl.getName());
1083
1084        int classaccess = cl.getModifiers();
1085        classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
1086                Modifier.INTERFACE | Modifier.ABSTRACT);
1087
1088        /* Workaround for javac bug that only set ABSTRACT for
1089         * interfaces if the interface had some methods.
1090         * The ABSTRACT bit reflects that the number of methods > 0.
1091         * This is required so correct hashes can be computed
1092         * for existing class files.
1093         * Previously this hack was previously present in the VM.
1094         */

1095            Method JavaDoc[] method = cl.getDeclaredMethods();
1096        if ((classaccess & Modifier.INTERFACE) != 0) {
1097        classaccess &= (~Modifier.ABSTRACT);
1098        if (method.length > 0) {
1099            classaccess |= Modifier.ABSTRACT;
1100        }
1101        }
1102
1103        // Mask out any post-1.4 attributes
1104
classaccess &= CLASS_MASK ;
1105
1106        if (DEBUG_SVUID)
1107        msg( "\twriteInt( " + classaccess + " ) " ) ;
1108        data.writeInt(classaccess);
1109
1110        /*
1111         * Get the list of interfaces supported,
1112         * Accumulate their names their names in Lexical order
1113         * and add them to the hash
1114         */

1115            if (!cl.isArray()) {
1116                /* In 1.2fcs, getInterfaces() was modified to return
1117                 * {java.lang.Cloneable, java.io.Serializable} when
1118                 * called on array classes. These values would upset
1119                 * the computation of the hash, so we explicitly omit
1120                 * them from its computation.
1121                 */

1122
1123            Class JavaDoc interfaces[] = cl.getInterfaces();
1124            Arrays.sort(interfaces, compareClassByName);
1125
1126            for (int i = 0; i < interfaces.length; i++) {
1127            if (DEBUG_SVUID)
1128            msg( "\twriteUTF( \"" + interfaces[i].getName() + "\" ) " ) ;
1129            data.writeUTF(interfaces[i].getName());
1130            }
1131        }
1132
1133        /* Sort the field names to get a deterministic order */
1134            Field JavaDoc[] field = cl.getDeclaredFields();
1135        Arrays.sort(field, compareMemberByName);
1136
1137        for (int i = 0; i < field.length; i++) {
1138        Field JavaDoc f = field[i];
1139
1140        /* Include in the hash all fields except those that are
1141         * private transient and private static.
1142         */

1143        int m = f.getModifiers();
1144        if (Modifier.isPrivate(m) &&
1145            (Modifier.isTransient(m) || Modifier.isStatic(m)))
1146            continue;
1147
1148        if (DEBUG_SVUID)
1149            msg( "\twriteUTF( \"" + f.getName() + "\" ) " ) ;
1150        data.writeUTF(f.getName());
1151
1152        // Mask out any post-1.4 bits
1153
m &= FIELD_MASK ;
1154
1155        if (DEBUG_SVUID)
1156            msg( "\twriteInt( " + m + " ) " ) ;
1157        data.writeInt(m);
1158
1159        if (DEBUG_SVUID)
1160            msg( "\twriteUTF( \"" + getSignature(f.getType()) + "\" ) " ) ;
1161        data.writeUTF(getSignature(f.getType()));
1162        }
1163
1164        if (hasStaticInitializer(cl)) {
1165        if (DEBUG_SVUID)
1166            msg( "\twriteUTF( \"<clinit>\" ) " ) ;
1167        data.writeUTF("<clinit>");
1168
1169        if (DEBUG_SVUID)
1170            msg( "\twriteInt( " + Modifier.STATIC + " )" ) ;
1171        data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
1172

1173        if (DEBUG_SVUID)
1174            msg( "\twriteUTF( \"()V\" )" ) ;
1175        data.writeUTF("()V");
1176        }
1177
1178        /*
1179         * Get the list of constructors including name and signature
1180         * Sort lexically, add all except the private constructors
1181         * to the hash with their access flags
1182         */

1183
1184        MethodSignature[] constructors =
1185        MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
1186        for (int i = 0; i < constructors.length; i++) {
1187        MethodSignature c = constructors[i];
1188        String JavaDoc mname = "<init>";
1189        String JavaDoc desc = c.signature;
1190        desc = desc.replace('/', '.');
1191        if (DEBUG_SVUID)
1192            msg( "\twriteUTF( \"" + mname + "\" )" ) ;
1193        data.writeUTF(mname);
1194
1195        // mask out post-1.4 modifiers
1196
int modifier = c.member.getModifiers() & METHOD_MASK ;
1197
1198        if (DEBUG_SVUID)
1199            msg( "\twriteInt( " + modifier + " ) " ) ;
1200        data.writeInt( modifier ) ;
1201
1202        if (DEBUG_SVUID)
1203            msg( "\twriteUTF( \"" + desc+ "\" )" ) ;
1204        data.writeUTF(desc);
1205        }
1206
1207        /* Include in the hash all methods except those that are
1208         * private transient and private static.
1209         */

1210        MethodSignature[] methods =
1211        MethodSignature.removePrivateAndSort(method);
1212        for (int i = 0; i < methods.length; i++ ) {
1213        MethodSignature m = methods[i];
1214        String JavaDoc desc = m.signature;
1215        desc = desc.replace('/', '.');
1216
1217        if (DEBUG_SVUID)
1218            msg( "\twriteUTF( \"" + m.member.getName()+ "\" )" ) ;
1219        data.writeUTF(m.member.getName());
1220
1221        // mask out post-1.4 modifiers
1222
int modifier = m.member.getModifiers() & METHOD_MASK ;
1223
1224        if (DEBUG_SVUID)
1225            msg( "\twriteInt( " + modifier + " ) " ) ;
1226        data.writeInt( modifier ) ;
1227
1228        if (DEBUG_SVUID)
1229            msg( "\twriteUTF( \"" + desc + "\" )" ) ;
1230        data.writeUTF(desc);
1231        }
1232
1233        /* Compute the hash value for this class.
1234         * Use only the first 64 bits of the hash.
1235         */

1236        data.flush();
1237        byte hasharray[] = md.digest();
1238        for (int i = 0; i < Math.min(8, hasharray.length); i++) {
1239        h += (long)(hasharray[i] & 255) << (i * 8);
1240        }
1241    } catch (IOException JavaDoc ignore) {
1242        /* can't happen, but be deterministic anyway. */
1243        h = -1;
1244    } catch (NoSuchAlgorithmException JavaDoc complain) {
1245        SecurityException JavaDoc se = new SecurityException JavaDoc() ;
1246        se.initCause( complain ) ;
1247        throw se ;
1248    }
1249
1250    return h;
1251    }
1252
1253    private static long computeStructuralUID(com.sun.corba.se.impl.io.ObjectStreamClass osc, Class JavaDoc cl) {
1254    ByteArrayOutputStream JavaDoc devnull = new ByteArrayOutputStream JavaDoc(512);
1255        
1256    long h = 0;
1257    try {
1258
1259        if ((!java.io.Serializable JavaDoc.class.isAssignableFrom(cl)) ||
1260        (cl.isInterface())){
1261        return 0;
1262        }
1263            
1264        if (java.io.Externalizable JavaDoc.class.isAssignableFrom(cl)) {
1265        return 1;
1266        }
1267
1268        MessageDigest JavaDoc md = MessageDigest.getInstance("SHA");
1269        DigestOutputStream JavaDoc mdo = new DigestOutputStream JavaDoc(devnull, md);
1270        DataOutputStream JavaDoc data = new DataOutputStream JavaDoc(mdo);
1271
1272        // Get SUID of parent
1273
Class JavaDoc parent = cl.getSuperclass();
1274        if ((parent != null))
1275        // SerialBug 1; acc. to spec the one for
1276
// java.lang.object
1277
// should be computed and put
1278
// && (parent != java.lang.Object.class))
1279
{
1280                //data.writeLong(computeSerialVersionUID(null,parent));
1281
data.writeLong(computeStructuralUID(lookup(parent), parent));
1282        }
1283
1284        if (osc.hasWriteObject())
1285        data.writeInt(2);
1286        else
1287        data.writeInt(1);
1288
1289            // CORBA formal 00-11-03 10.6.2: For each field of the
1290
// class that is mapped to IDL, sorted lexicographically
1291
// by Java field name, in increasing order...
1292
ObjectStreamField[] field = osc.getFields();
1293            if (field.length > 1) {
1294                Arrays.sort(field, compareObjStrFieldsByName);
1295            }
1296
1297            // ...Java field name in UTF encoding, field
1298
// descriptor, as defined by the JVM spec...
1299
for (int i = 0; i < field.length; i++) {
1300                data.writeUTF(field[i].getName());
1301                data.writeUTF(field[i].getSignature());
1302            }
1303            
1304        /* Compute the hash value for this class.
1305         * Use only the first 64 bits of the hash.
1306         */

1307        data.flush();
1308        byte hasharray[] = md.digest();
1309        // int minimum = Math.min(8, hasharray.length);
1310
// SerialBug 3: SHA computation is wrong; for loop reversed
1311
//for (int i = minimum; i > 0; i--)
1312
for (int i = 0; i < Math.min(8, hasharray.length); i++) {
1313        h += (long)(hasharray[i] & 255) << (i * 8);
1314        }
1315    } catch (IOException JavaDoc ignore) {
1316        /* can't happen, but be deterministic anyway. */
1317        h = -1;
1318    } catch (NoSuchAlgorithmException JavaDoc complain) {
1319        SecurityException JavaDoc se = new SecurityException JavaDoc();
1320        se.initCause( complain ) ;
1321        throw se ;
1322    }
1323    return h;
1324    }
1325
1326    /**
1327     * Compute the JVM signature for the class.
1328     */

1329    static String JavaDoc getSignature(Class JavaDoc clazz) {
1330    String JavaDoc type = null;
1331    if (clazz.isArray()) {
1332        Class JavaDoc cl = clazz;
1333        int dimensions = 0;
1334        while (cl.isArray()) {
1335        dimensions++;
1336        cl = cl.getComponentType();
1337        }
1338        StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1339        for (int i = 0; i < dimensions; i++) {
1340        sb.append("[");
1341        }
1342        sb.append(getSignature(cl));
1343        type = sb.toString();
1344    } else if (clazz.isPrimitive()) {
1345        if (clazz == Integer.TYPE) {
1346        type = "I";
1347        } else if (clazz == Byte.TYPE) {
1348        type = "B";
1349        } else if (clazz == Long.TYPE) {
1350        type = "J";
1351        } else if (clazz == Float.TYPE) {
1352        type = "F";
1353        } else if (clazz == Double.TYPE) {
1354        type = "D";
1355        } else if (clazz == Short.TYPE) {
1356        type = "S";
1357        } else if (clazz == Character.TYPE) {
1358        type = "C";
1359        } else if (clazz == Boolean.TYPE) {
1360        type = "Z";
1361        } else if (clazz == Void.TYPE) {
1362        type = "V";
1363        }
1364    } else {
1365        type = "L" + clazz.getName().replace('.', '/') + ";";
1366    }
1367    return type;
1368    }
1369
1370    /*
1371     * Compute the JVM method descriptor for the method.
1372     */

1373    static String JavaDoc getSignature(Method JavaDoc meth) {
1374    StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1375
1376    sb.append("(");
1377
1378    Class JavaDoc[] params = meth.getParameterTypes(); // avoid clone
1379
for (int j = 0; j < params.length; j++) {
1380        sb.append(getSignature(params[j]));
1381    }
1382    sb.append(")");
1383    sb.append(getSignature(meth.getReturnType()));
1384    return sb.toString();
1385    }
1386
1387    /*
1388     * Compute the JVM constructor descriptor for the constructor.
1389     */

1390    static String JavaDoc getSignature(Constructor JavaDoc cons) {
1391    StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1392
1393    sb.append("(");
1394
1395    Class JavaDoc[] params = cons.getParameterTypes(); // avoid clone
1396
for (int j = 0; j < params.length; j++) {
1397        sb.append(getSignature(params[j]));
1398    }
1399    sb.append(")V");
1400    return sb.toString();
1401    }
1402
1403    static private SoftCache descriptorFor = new SoftCache() ;
1404
1405    private static Field JavaDoc[] getDeclaredFields(final Class JavaDoc clz) {
1406        return (Field JavaDoc[]) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
1407            public Object JavaDoc run() {
1408                return clz.getDeclaredFields();
1409            }
1410        });
1411    }
1412
1413
1414    /*
1415     * The name of this descriptor
1416     */

1417    private String JavaDoc name;
1418
1419    /*
1420     * The descriptor of the supertype.
1421     */

1422    private ObjectStreamClass superclass;
1423
1424    /*
1425     * Flags for Serializable and Externalizable.
1426     */

1427    private boolean serializable;
1428    private boolean externalizable;
1429
1430    /*
1431     * Array of persistent fields of this class, sorted by
1432     * type and name.
1433     */

1434    private ObjectStreamField[] fields;
1435
1436    /*
1437     * Class that is a descriptor for in this virtual machine.
1438     */

1439    private Class JavaDoc ofClass;
1440
1441    /*
1442     * True if descriptor for a proxy class.
1443     */

1444    boolean forProxyClass;
1445
1446
1447    /*
1448     * SerialVersionUID for this class.
1449     */

1450    private long suid = kDefaultUID;
1451    private String JavaDoc suidStr = null;
1452
1453    /*
1454     * Actual (computed) SerialVersionUID for this class.
1455     */

1456    private long actualSuid = kDefaultUID;
1457    private String JavaDoc actualSuidStr = null;
1458
1459    /*
1460     * The total number of bytes of primitive fields.
1461     * The total number of object fields.
1462     */

1463    int primBytes;
1464    int objFields;
1465
1466    /**
1467     * Flag indicating whether or not this instance has
1468     * successfully completed initialization. This is to
1469     * try to fix bug 4373844. Working to move to
1470     * reusing java.io.ObjectStreamClass for JDK 1.5.
1471     */

1472    private boolean initialized = false;
1473
1474    /* Internal lock object. */
1475    private Object JavaDoc lock = new Object JavaDoc();
1476
1477    /* In JDK 1.1, external data was not written in block mode.
1478     * As of JDK 1.2, external data is written in block data mode. This
1479     * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
1480     *
1481     * @since JDK 1.2
1482     */

1483    private boolean hasExternalizableBlockData;
1484    Method JavaDoc writeObjectMethod;
1485    Method JavaDoc readObjectMethod;
1486    private Method JavaDoc writeReplaceObjectMethod;
1487    private Method JavaDoc readResolveObjectMethod;
1488    private Constructor JavaDoc cons ;
1489
1490    /**
1491     * Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a
1492     * stream format version 2 which puts a fake valuetype around
1493     * a Serializable's optional custom data. This valuetype has
1494     * a special repository ID made from the Serializable's
1495     * information which we are pre-computing and
1496     * storing here.
1497     */

1498    private String JavaDoc rmiiiopOptionalDataRepId = null;
1499
1500    /*
1501     * ObjectStreamClass that this one was built from.
1502     */

1503    private ObjectStreamClass localClassDesc;
1504
1505    /* Find out if the class has a static class initializer <clinit> */
1506    private static Method JavaDoc hasStaticInitializerMethod = null;
1507    /**
1508     * Returns true if the given class defines a static initializer method,
1509     * false otherwise.
1510     */

1511    private static boolean hasStaticInitializer(Class JavaDoc cl) {
1512        if (hasStaticInitializerMethod == null) {
1513            Class JavaDoc classWithThisMethod = null;
1514            
1515            try {
1516                try {
1517                    // When using rip-int with Merlin or when this is a Merlin
1518
// workspace, the method we want is in sun.misc.ClassReflector
1519
// and absent from java.io.ObjectStreamClass.
1520
//
1521
// When compiling rip-int with JDK 1.3.x, we have to get it
1522
// from java.io.ObjectStreamClass.
1523
classWithThisMethod = Class.forName("sun.misc.ClassReflector");
1524                } catch (ClassNotFoundException JavaDoc cnfe) {
1525                    // Do nothing. This is either not a Merlin workspace,
1526
// or rip-int is being compiled with something other than
1527
// Merlin, probably JDK 1.3. Fall back on java.io.ObjectStreaClass.
1528
}
1529                if (classWithThisMethod == null)
1530                    classWithThisMethod = java.io.ObjectStreamClass JavaDoc.class;
1531                
1532                hasStaticInitializerMethod =
1533                    classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
1534                                                          new Class JavaDoc[] { Class JavaDoc.class });
1535            } catch (NoSuchMethodException JavaDoc ex) {
1536            }
1537            
1538            if (hasStaticInitializerMethod == null) {
1539        // XXX I18N, logging needed
1540
throw new InternalError JavaDoc("Can't find hasStaticInitializer method on "
1541                                        + classWithThisMethod.getName());
1542            }
1543            hasStaticInitializerMethod.setAccessible(true);
1544        }
1545
1546        try {
1547            Boolean JavaDoc retval = (Boolean JavaDoc)
1548                hasStaticInitializerMethod.invoke(null, new Object JavaDoc[] { cl });
1549            return retval.booleanValue();
1550        } catch (Exception JavaDoc ex) {
1551        // XXX I18N, logging needed
1552
InternalError JavaDoc ie = new InternalError JavaDoc( "Error invoking hasStaticInitializer" ) ;
1553        ie.initCause( ex ) ;
1554        throw ie ;
1555        }
1556    }
1557
1558
1559    /* The Class Object for java.io.Serializable */
1560    private static Class JavaDoc classSerializable = null;
1561    private static Class JavaDoc classExternalizable = null;
1562
1563    /*
1564     * Resolve java.io.Serializable at load time.
1565     */

1566    static {
1567    try {
1568        classSerializable = Class.forName("java.io.Serializable");
1569        classExternalizable = Class.forName("java.io.Externalizable");
1570    } catch (Throwable JavaDoc e) {
1571        System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
1572    }
1573    }
1574
1575    /** use serialVersionUID from JDK 1.1. for interoperability */
1576    private static final long serialVersionUID = -6120832682080437368L;
1577
1578    /**
1579     * Set serialPersistentFields of a Serializable class to this value to
1580     * denote that the class has no Serializable fields.
1581     */

1582    public static final ObjectStreamField[] NO_FIELDS =
1583        new ObjectStreamField[0];
1584
1585    /*
1586     * Entries held in the Cache of known ObjectStreamClass objects.
1587     * Entries are chained together with the same hash value (modulo array size).
1588     */

1589    private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
1590
{
1591    ObjectStreamClassEntry(ObjectStreamClass c) {
1592        //super(c);
1593
this.c = c;
1594    }
1595    ObjectStreamClassEntry next;
1596
1597    public Object JavaDoc get()
1598    {
1599        return c;
1600    }
1601    private ObjectStreamClass c;
1602    }
1603
1604    /*
1605     * Comparator object for Classes and Interfaces
1606     */

1607    private static Comparator JavaDoc compareClassByName =
1608        new CompareClassByName();
1609
1610    private static class CompareClassByName implements Comparator JavaDoc {
1611    public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1612        Class JavaDoc c1 = (Class JavaDoc)o1;
1613        Class JavaDoc c2 = (Class JavaDoc)o2;
1614        return (c1.getName()).compareTo(c2.getName());
1615    }
1616    }
1617
1618    /**
1619     * Comparator for ObjectStreamFields by name
1620     */

1621    private final static Comparator JavaDoc compareObjStrFieldsByName
1622        = new CompareObjStrFieldsByName();
1623
1624    private static class CompareObjStrFieldsByName implements Comparator JavaDoc {
1625        public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1626            ObjectStreamField osf1 = (ObjectStreamField)o1;
1627            ObjectStreamField osf2 = (ObjectStreamField)o2;
1628
1629            return osf1.getName().compareTo(osf2.getName());
1630        }
1631    }
1632
1633    /*
1634     * Comparator object for Members, Fields, and Methods
1635     */

1636    private static Comparator JavaDoc compareMemberByName =
1637        new CompareMemberByName();
1638
1639    private static class CompareMemberByName implements Comparator JavaDoc {
1640    public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1641        String JavaDoc s1 = ((Member JavaDoc)o1).getName();
1642        String JavaDoc s2 = ((Member JavaDoc)o2).getName();
1643
1644        if (o1 instanceof Method JavaDoc) {
1645        s1 += getSignature((Method JavaDoc)o1);
1646        s2 += getSignature((Method JavaDoc)o2);
1647        } else if (o1 instanceof Constructor JavaDoc) {
1648        s1 += getSignature((Constructor JavaDoc)o1);
1649        s2 += getSignature((Constructor JavaDoc)o2);
1650        }
1651        return s1.compareTo(s2);
1652    }
1653    }
1654
1655    /* It is expensive to recompute a method or constructor signature
1656       many times, so compute it only once using this data structure. */

1657    private static class MethodSignature implements Comparator JavaDoc {
1658    Member JavaDoc member;
1659    String JavaDoc signature; // cached parameter signature
1660

1661    /* Given an array of Method or Constructor members,
1662       return a sorted array of the non-private members.*/

1663    /* A better implementation would be to implement the returned data
1664       structure as an insertion sorted link list.*/

1665    static MethodSignature[] removePrivateAndSort(Member JavaDoc[] m) {
1666        int numNonPrivate = 0;
1667        for (int i = 0; i < m.length; i++) {
1668        if (! Modifier.isPrivate(m[i].getModifiers())) {
1669            numNonPrivate++;
1670        }
1671        }
1672        MethodSignature[] cm = new MethodSignature[numNonPrivate];
1673        int cmi = 0;
1674        for (int i = 0; i < m.length; i++) {
1675        if (! Modifier.isPrivate(m[i].getModifiers())) {
1676            cm[cmi] = new MethodSignature(m[i]);
1677            cmi++;
1678        }
1679        }
1680        if (cmi > 0)
1681        Arrays.sort(cm, cm[0]);
1682        return cm;
1683    }
1684
1685    /* Assumes that o1 and o2 are either both methods
1686       or both constructors.*/

1687    public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1688        /* Arrays.sort calls compare when o1 and o2 are equal.*/
1689        if (o1 == o2)
1690        return 0;
1691
1692        MethodSignature c1 = (MethodSignature)o1;
1693        MethodSignature c2 = (MethodSignature)o2;
1694
1695        int result;
1696        if (isConstructor()) {
1697        result = c1.signature.compareTo(c2.signature);
1698        } else { // is a Method.
1699
result = c1.member.getName().compareTo(c2.member.getName());
1700        if (result == 0)
1701            result = c1.signature.compareTo(c2.signature);
1702        }
1703        return result;
1704    }
1705
1706    final private boolean isConstructor() {
1707        return member instanceof Constructor JavaDoc;
1708    }
1709    private MethodSignature(Member JavaDoc m) {
1710        member = m;
1711        if (isConstructor()) {
1712        signature = ObjectStreamClass.getSignature((Constructor JavaDoc)m);
1713        } else {
1714        signature = ObjectStreamClass.getSignature((Method JavaDoc)m);
1715        }
1716    }
1717    }
1718
1719    /**
1720     * Returns non-static, non-abstract method with given signature provided it
1721     * is defined by or accessible (via inheritance) by the given class, or
1722     * null if no match found. Access checks are disabled on the returned
1723     * method (if any).
1724     *
1725     * Copied from the Merlin java.io.ObjectStreamClass.
1726     */

1727    private static Method JavaDoc getInheritableMethod(Class JavaDoc cl, String JavaDoc name,
1728                           Class JavaDoc[] argTypes,
1729                           Class JavaDoc returnType)
1730    {
1731    Method JavaDoc meth = null;
1732    Class JavaDoc defCl = cl;
1733    while (defCl != null) {
1734        try {
1735        meth = defCl.getDeclaredMethod(name, argTypes);
1736        break;
1737        } catch (NoSuchMethodException JavaDoc ex) {
1738        defCl = defCl.getSuperclass();
1739        }
1740    }
1741
1742    if ((meth == null) || (meth.getReturnType() != returnType)) {
1743        return null;
1744    }
1745    meth.setAccessible(true);
1746    int mods = meth.getModifiers();
1747    if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
1748        return null;
1749    } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
1750        return meth;
1751    } else if ((mods & Modifier.PRIVATE) != 0) {
1752        return (cl == defCl) ? meth : null;
1753    } else {
1754        return packageEquals(cl, defCl) ? meth : null;
1755    }
1756    }
1757
1758    /**
1759     * Returns true if classes are defined in the same package, false
1760     * otherwise.
1761     *
1762     * Copied from the Merlin java.io.ObjectStreamClass.
1763     */

1764    private static boolean packageEquals(Class JavaDoc cl1, Class JavaDoc cl2) {
1765    Package JavaDoc pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage();
1766    return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2))));
1767    }
1768}
1769
Popular Tags