KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > corba > se > impl > orbutil > ObjectStreamClass_1_3_1


1 /*
2  * @(#)ObjectStreamClass_1_3_1.java 1.6 04/01/12
3  *
4  * Copyright 2004 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.orbutil;
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 org.omg.CORBA.ValueMember JavaDoc;
46
47 import com.sun.corba.se.impl.io.ValueUtility;
48 import com.sun.corba.se.impl.io.ObjectStreamClass;
49
50 /**
51  * This is duplicated here to preserve the JDK 1.3.1FCS behavior
52  * of calculating the OMG hash code incorrectly when serialPersistentFields
53  * is used, but some of the fields no longer exist in the class itself.
54  *
55  * We have to duplicate it since we aren't allowed to modify the
56  * com.sun.corba.se.impl.io version further, and can't make it
57  * public outside of its package for security reasons.
58  */

59 /**
60  * A ObjectStreamClass_1_3_1 describes a class that can be serialized to a stream
61  * or a class that was serialized to a stream. It contains the name
62  * and the serialVersionUID of the class.
63  * <br>
64  * The ObjectStreamClass_1_3_1 for a specific class loaded in this Java VM can
65  * be found using the lookup method.
66  *
67  * @author Roger Riggs
68  * @(#)ObjectStreamClass_1_3_1.java 1.17 99/06/07
69  * @since JDK1.1
70  */

71 public class ObjectStreamClass_1_3_1 implements java.io.Serializable JavaDoc {
72
73     public static final long kDefaultUID = -1;
74
75     private static Object JavaDoc noArgsList[] = {};
76     private static Class JavaDoc noTypesList[] = {};
77     
78     private static Hashtable JavaDoc translatedFields;
79
80     /** Find the descriptor for a class that can be serialized. Null
81      * is returned if the specified class does not implement
82      * java.io.Serializable or java.io.Externalizable.
83      */

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

96     static ObjectStreamClass_1_3_1 lookupInternal(Class JavaDoc cl)
97     {
98     /* Synchronize on the hashtable so no two threads will do
99      * this at the same time.
100      */

101     ObjectStreamClass_1_3_1 desc = null;
102     synchronized (descriptorFor) {
103         /* Find the matching descriptor if it already known */
104         desc = findDescriptorFor(cl);
105         if (desc != null) {
106         return desc;
107         }
108
109                 /* Check if it's serializable */
110                 boolean serializable = classSerializable.isAssignableFrom(cl);
111                 /* If the class is only Serializable,
112                  * lookup the descriptor for the superclass.
113                  */

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

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

138         desc = new ObjectStreamClass_1_3_1(cl, superdesc,
139                      serializable, externalizable);
140     }
141     desc.init();
142     return desc;
143     }
144
145     /**
146      * The name of the class described by this descriptor.
147      */

148     public final String JavaDoc getName() {
149     return name;
150     }
151
152     /**
153      * Return the serialVersionUID for this class.
154      * The serialVersionUID defines a set of classes all with the same name
155      * that have evolved from a common root class and agree to be serialized
156      * and deserialized using a common format.
157      */

158     public static final long getSerialVersionUID( java.lang.Class JavaDoc clazz) {
159     ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
160         if( theosc != null )
161     {
162         return theosc.getSerialVersionUID( );
163     }
164     return 0;
165     }
166
167     /**
168      * Return the serialVersionUID for this class.
169      * The serialVersionUID defines a set of classes all with the same name
170      * that have evolved from a common root class and agree to be serialized
171      * and deserialized using a common format.
172      */

173     public final long getSerialVersionUID() {
174     return suid;
175     }
176
177     /**
178      * Return the serialVersionUID string for this class.
179      * The serialVersionUID defines a set of classes all with the same name
180      * that have evolved from a common root class and agree to be serialized
181      * and deserialized using a common format.
182      */

183     public final String JavaDoc getSerialVersionUIDStr() {
184     if (suidStr == null)
185         suidStr = Long.toHexString(suid).toUpperCase();
186     return suidStr;
187     }
188
189     /**
190      * Return the actual (computed) serialVersionUID for this class.
191      */

192     public static final long getActualSerialVersionUID( java.lang.Class JavaDoc clazz )
193     {
194     ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
195     if( theosc != null )
196     {
197         return theosc.getActualSerialVersionUID( );
198     }
199     return 0;
200     }
201
202     /**
203      * Return the actual (computed) serialVersionUID for this class.
204      */

205     public final long getActualSerialVersionUID() {
206     return actualSuid;
207     }
208
209     /**
210      * Return the actual (computed) serialVersionUID for this class.
211      */

212     public final String JavaDoc getActualSerialVersionUIDStr() {
213     if (actualSuidStr == null)
214         actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
215     return actualSuidStr;
216     }
217
218     /**
219      * Return the class in the local VM that this version is mapped to.
220      * Null is returned if there is no corresponding local class.
221      */

222     public final Class JavaDoc forClass() {
223     return ofClass;
224     }
225
226     /**
227      * Return an array of the fields of this serializable class.
228      * @return an array containing an element for each persistent
229      * field of this class. Returns an array of length zero if
230      * there are no fields.
231      * @since JDK1.2
232      */

233     public ObjectStreamField[] getFields() {
234         // Return a copy so the caller can't change the fields.
235
if (fields.length > 0) {
236         ObjectStreamField[] dup = new ObjectStreamField[fields.length];
237         System.arraycopy(fields, 0, dup, 0, fields.length);
238         return dup;
239     } else {
240         return fields;
241     }
242     }
243
244     public boolean hasField(ValueMember JavaDoc field){
245
246     for (int i = 0; i < fields.length; i++){
247         try{
248         if (fields[i].getName().equals(field.name)) {
249
250             if (fields[i].getSignature().equals(ValueUtility.getSignature(field)))
251             return true;
252         }
253         }
254         catch(Throwable JavaDoc t){}
255     }
256     return false;
257     }
258
259     /* Avoid unnecessary allocations. */
260     final ObjectStreamField[] getFieldsNoCopy() {
261     return fields;
262     }
263
264     /**
265      * Get the field of this class by name.
266      * @return The ObjectStreamField object of the named field or null if there
267      * is no such named field.
268      */

269     public final ObjectStreamField getField(String JavaDoc name) {
270         /* Binary search of fields by name.
271      */

272         for (int i = fields.length-1; i >= 0; i--) {
273             if (name.equals(fields[i].getName())) {
274                 return fields[i];
275         }
276         }
277     return null;
278     }
279
280     public Serializable JavaDoc writeReplace(Serializable JavaDoc value) {
281     if (writeReplaceObjectMethod != null) {
282         try {
283         return (Serializable JavaDoc) writeReplaceObjectMethod.invoke(value,noArgsList);
284         }
285         catch(Throwable JavaDoc t) {
286         throw new RuntimeException JavaDoc(t.getMessage());
287         }
288     }
289     else return value;
290     }
291
292     public Object JavaDoc readResolve(Object JavaDoc value) {
293     if (readResolveObjectMethod != null) {
294         try {
295         return readResolveObjectMethod.invoke(value,noArgsList);
296         }
297         catch(Throwable JavaDoc t) {
298         throw new RuntimeException JavaDoc(t.getMessage());
299         }
300     }
301     else return value;
302     }
303
304     /**
305      * Return a string describing this ObjectStreamClass_1_3_1.
306      */

307     public final String JavaDoc toString() {
308     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
309
310     sb.append(name);
311     sb.append(": static final long serialVersionUID = ");
312     sb.append(Long.toString(suid));
313     sb.append("L;");
314     return sb.toString();
315     }
316
317     /*
318      * Create a new ObjectStreamClass_1_3_1 from a loaded class.
319      * Don't call this directly, call lookup instead.
320      */

321     private ObjectStreamClass_1_3_1(java.lang.Class JavaDoc cl, ObjectStreamClass_1_3_1 superdesc,
322                   boolean serial, boolean extern)
323     {
324     ofClass = cl; /* created from this class */
325
326         if (Proxy.isProxyClass(cl)) {
327             forProxyClass = true;
328         }
329
330     name = cl.getName();
331     superclass = superdesc;
332     serializable = serial;
333         if (!forProxyClass) {
334             // proxy classes are never externalizable
335
externalizable = extern;
336         }
337
338     /*
339      * Enter this class in the table of known descriptors.
340      * Otherwise, when the fields are read it may recurse
341      * trying to find the descriptor for itself.
342      */

343     insertDescriptorFor(this);
344
345         /*
346          * The remainder of initialization occurs in init(), which is called
347          * after the lock on the global class descriptor table has been
348          * released.
349          */

350     }
351
352     /*
353      * Initialize class descriptor. This method is only invoked on class
354      * descriptors created via calls to lookupInternal(). This method is kept
355      * separate from the ObjectStreamClass_1_3_1 constructor so that lookupInternal
356      * does not have to hold onto a global class descriptor table lock while the
357      * class descriptor is being initialized (see bug 4165204).
358      */

359
360
361     private void init() {
362       synchronized (lock) {
363
364     final Class JavaDoc cl = ofClass;
365  
366     if (fields != null) // already initialized
367
return;
368
369
370     if (!serializable ||
371         externalizable ||
372         forProxyClass ||
373         name.equals("java.lang.String")) {
374         fields = NO_FIELDS;
375     } else if (serializable) {
376
377             /* Ask for permission to override field access checks.
378              */

379             AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
380                 public Object JavaDoc run() {
381         /* Fill in the list of persistent fields.
382          * If it is declared, use the declared serialPersistentFields.
383          * Otherwise, extract the fields from the class itself.
384          */

385         try {
386                     Field JavaDoc pf = cl.getDeclaredField("serialPersistentFields");
387                 // serial bug 7; the serialPersistentFields were not
388
// being read and stored as Accessible bit was not set
389
pf.setAccessible(true);
390                 // serial bug 7; need to find if the field is of type
391
// java.io.ObjectStreamField
392
java.io.ObjectStreamField JavaDoc[] f =
393                            (java.io.ObjectStreamField JavaDoc[])pf.get(cl);
394             int mods = pf.getModifiers();
395             if ((Modifier.isPrivate(mods)) &&
396             (Modifier.isStatic(mods)) &&
397             (Modifier.isFinal(mods)))
398                 {
399             fields = (ObjectStreamField[])translateFields((Object JavaDoc[])pf.get(cl));
400             }
401         } catch (NoSuchFieldException JavaDoc e) {
402             fields = null;
403         } catch (IllegalAccessException JavaDoc e) {
404             fields = null;
405         } catch (IllegalArgumentException JavaDoc e) {
406             fields = null;
407                 } catch (ClassCastException JavaDoc e) {
408                     /* Thrown if a field serialPersistentField exists
409                      * but it is not of type ObjectStreamField.
410                      */

411                     fields = null;
412                 }
413
414
415         if (fields == null) {
416             /* Get all of the declared fields for this
417              * Class. setAccessible on all fields so they
418              * can be accessed later. Create a temporary
419              * ObjectStreamField array to hold each
420              * non-static, non-transient field. Then copy the
421              * temporary array into an array of the correct
422              * size once the number of fields is known.
423              */

424                     Field JavaDoc[] actualfields = cl.getDeclaredFields();
425
426             int numFields = 0;
427             ObjectStreamField[] tempFields =
428             new ObjectStreamField[actualfields.length];
429             for (int i = 0; i < actualfields.length; i++) {
430             int modifiers = actualfields[i].getModifiers();
431             if (!Modifier.isStatic(modifiers) &&
432                 !Modifier.isTransient(modifiers)) {
433                 tempFields[numFields++] =
434                 new ObjectStreamField(actualfields[i]);
435             }
436             }
437             fields = new ObjectStreamField[numFields];
438             System.arraycopy(tempFields, 0, fields, 0, numFields);
439
440         } else {
441             // For each declared persistent field, look for an actual
442
// reflected Field. If there is one, make sure it's the correct
443
// type and cache it in the ObjectStreamClass_1_3_1 for that field.
444
for (int j = fields.length-1; j >= 0; j--) {
445             try {
446                             Field JavaDoc reflField = cl.getDeclaredField(fields[j].getName());
447                 if (fields[j].getType() == reflField.getType()) {
448                 // reflField.setAccessible(true);
449
fields[j].setField(reflField);
450                 }
451             } catch (NoSuchFieldException JavaDoc e) {
452                 // Nothing to do
453
}
454             }
455         }
456             return null;
457         }
458         });
459
460         if (fields.length > 1)
461         Arrays.sort(fields);
462
463         /* Set up field data for use while writing using the API api. */
464         computeFieldInfo();
465     }
466
467         /* Get the serialVersionUID from the class.
468          * It uses the access override mechanism so make sure
469          * the field objects is only used here.
470          *
471          * NonSerializable classes have a serialVerisonUID of 0L.
472          */

473          if (isNonSerializable()) {
474              suid = 0L;
475          } else {
476              // Lookup special Serializable members using reflection.
477
AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
478                 public Object JavaDoc run() {
479                 if (forProxyClass) {
480                     // proxy classes always have serialVersionUID of 0L
481
suid = 0L;
482                 } else {
483                 try {
484                         final Field JavaDoc f = cl.getDeclaredField("serialVersionUID");
485                     int mods = f.getModifiers();
486             // SerialBug 5: static final SUID should be read
487
if (Modifier.isStatic(mods) &&
488                             Modifier.isFinal(mods) ) {
489                             f.setAccessible(true);
490                     suid = f.getLong(cl);
491                         // get rid of native code
492
// suid = getSerialVersionUIDField(cl);
493
// SerialBug 2: should be computed after writeObject
494
// actualSuid = computeStructuralUID(cl);
495
} else {
496                     suid = ObjectStreamClass.getSerialVersionUID(cl);
497                         // SerialBug 2: should be computed after writeObject
498
// actualSuid = computeStructuralUID(cl);
499
}
500                 } catch (NoSuchFieldException JavaDoc ex) {
501                     suid = ObjectStreamClass.getSerialVersionUID(cl);
502                     // SerialBug 2: should be computed after writeObject
503
// actualSuid = computeStructuralUID(cl);
504
} catch (IllegalAccessException JavaDoc ex) {
505                         suid = ObjectStreamClass.getSerialVersionUID(cl);
506                     }
507             }
508
509
510             try {
511                     writeReplaceObjectMethod = cl.getDeclaredMethod("writeReplace", noTypesList);
512                 if (Modifier.isStatic(writeReplaceObjectMethod.getModifiers())) {
513                     writeReplaceObjectMethod = null;
514                     } else {
515                         writeReplaceObjectMethod.setAccessible(true);
516                     }
517
518             } catch (NoSuchMethodException JavaDoc e2) {
519
520             }
521     
522             try {
523                     readResolveObjectMethod = cl.getDeclaredMethod("readResolve", noTypesList);
524                 if (Modifier.isStatic(readResolveObjectMethod.getModifiers())) {
525                    readResolveObjectMethod = null;
526                     } else {
527                        readResolveObjectMethod.setAccessible(true);
528                     }
529
530             } catch (NoSuchMethodException JavaDoc e2) {
531
532             }
533     
534                 /* Cache lookup of writeObject and readObject for
535                  * Serializable classes. (Do not lookup for
536                  * Externalizable)
537                  */

538
539                 if (serializable && !forProxyClass) {
540
541                 /* Look for the writeObject method
542                  * Set the accessible flag on it here. ObjectOutputStream
543                  * will call it as necessary.
544                  */

545                 try {
546                   Class JavaDoc[] args = {java.io.ObjectOutputStream JavaDoc.class};
547                       writeObjectMethod = cl.getDeclaredMethod("writeObject", args);
548                   hasWriteObjectMethod = true;
549                   int mods = writeObjectMethod.getModifiers();
550
551                   // Method must be private and non-static
552
if (!Modifier.isPrivate(mods) ||
553                 Modifier.isStatic(mods)) {
554                 writeObjectMethod = null;
555                 hasWriteObjectMethod = false;
556                   }
557
558                 } catch (NoSuchMethodException JavaDoc e) {
559                 }
560
561                 /* Look for the readObject method
562                  * set the access override and save the reference for
563                  * ObjectInputStream so it can all the method directly.
564                  */

565                 try {
566                   Class JavaDoc[] args = {java.io.ObjectInputStream JavaDoc.class};
567                       readObjectMethod = cl.getDeclaredMethod("readObject", args);
568                   int mods = readObjectMethod.getModifiers();
569
570                   // Method must be private and non-static
571
if (!Modifier.isPrivate(mods) ||
572                 Modifier.isStatic(mods)) {
573                 readObjectMethod = null;
574                   }
575                 } catch (NoSuchMethodException JavaDoc e) {
576                     }
577                     // Compute the structural UID. This must be done after the
578
// calculation for writeObject. Fixed 4/20/2000, eea1
579
// SerialBug 2: to have correct value in RepId
580
}
581             return null;
582         }
583       });
584     }
585
586         actualSuid = computeStructuralUID(this, cl);
587       }
588
589     }
590
591     /*
592      * Create an empty ObjectStreamClass_1_3_1 for a class about to be read.
593      * This is separate from read so ObjectInputStream can assign the
594      * wire handle early, before any nested ObjectStreamClass_1_3_1 might
595      * be read.
596      */

597     ObjectStreamClass_1_3_1(String JavaDoc n, long s) {
598     name = n;
599     suid = s;
600     superclass = null;
601     }
602
603     private static Object JavaDoc[] translateFields(Object JavaDoc objs[])
604         throws NoSuchFieldException JavaDoc {
605         try{
606             java.io.ObjectStreamField JavaDoc fields[] = (java.io.ObjectStreamField JavaDoc[])objs;
607             Object JavaDoc translation[] = null;
608                        
609             if (translatedFields == null)
610                 translatedFields = new Hashtable JavaDoc();
611                        
612             translation = (Object JavaDoc[])translatedFields.get(fields);
613                        
614             if (translation != null)
615                 return translation;
616             else {
617                 Class JavaDoc osfClass = com.sun.corba.se.impl.orbutil.ObjectStreamField.class;
618
619                 translation = (Object JavaDoc[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
620                 Object JavaDoc arg[] = new Object JavaDoc[2];
621                 Class JavaDoc types[] = {String JavaDoc.class, Class JavaDoc.class};
622                 Constructor JavaDoc constructor = osfClass.getDeclaredConstructor(types);
623                 for (int i = fields.length -1; i >= 0; i--){
624                     arg[0] = fields[i].getName();
625                     arg[1] = fields[i].getType();
626                        
627                     translation[i] = constructor.newInstance(arg);
628                 }
629                 translatedFields.put(fields, translation);
630                        
631             }
632
633             return (Object JavaDoc[])translation;
634         }
635         catch(Throwable JavaDoc t){
636             throw new NoSuchFieldException JavaDoc();
637         }
638     }
639
640     /* Compare the base class names of streamName and localName.
641      *
642      * @return Return true iff the base class name compare.
643      * @parameter streamName Fully qualified class name.
644      * @parameter localName Fully qualified class name.
645      * @parameter pkgSeparator class names use either '.' or '/'.
646      *
647      * Only compare base class name to allow package renaming.
648      */

649     static boolean compareClassNames(String JavaDoc streamName,
650                      String JavaDoc localName,
651                      char pkgSeparator) {
652     /* compare the class names, stripping off package names. */
653     int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
654     if (streamNameIndex < 0)
655         streamNameIndex = 0;
656
657     int localNameIndex = localName.lastIndexOf(pkgSeparator);
658     if (localNameIndex < 0)
659         localNameIndex = 0;
660
661     return streamName.regionMatches(false, streamNameIndex,
662                     localName, localNameIndex,
663                     streamName.length() - streamNameIndex);
664     }
665
666     /*
667      * Compare the types of two class descriptors.
668      * They match if they have the same class name and suid
669      */

670     final boolean typeEquals(ObjectStreamClass_1_3_1 other) {
671     return (suid == other.suid) &&
672         compareClassNames(name, other.name, '.');
673     }
674
675     /*
676      * Return the superclass descriptor of this descriptor.
677      */

678     final void setSuperclass(ObjectStreamClass_1_3_1 s) {
679     superclass = s;
680     }
681
682     /*
683      * Return the superclass descriptor of this descriptor.
684      */

685     final ObjectStreamClass_1_3_1 getSuperclass() {
686     return superclass;
687     }
688
689     /*
690      * Return whether the class has a writeObject method
691      */

692     final boolean hasWriteObject() {
693     return hasWriteObjectMethod;
694     }
695
696     final boolean isCustomMarshaled() {
697     return (hasWriteObject() || isExternalizable());
698     }
699
700     /*
701      * Return true if all instances of 'this' Externalizable class
702      * are written in block-data mode from the stream that 'this' was read
703      * from. <p>
704      *
705      * In JDK 1.1, all Externalizable instances are not written
706      * in block-data mode.
707      * In JDK 1.2, all Externalizable instances, by default, are written
708      * in block-data mode and the Externalizable instance is terminated with
709      * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
710      * instances.
711      *
712      * IMPLEMENTATION NOTE:
713      * This should have been a mode maintained per stream; however,
714      * for compatibility reasons, it was only possible to record
715      * this change per class. All Externalizable classes within
716      * a given stream should either have this mode enabled or
717      * disabled. This is enforced by not allowing the PROTOCOL_VERSION
718      * of a stream to he changed after any objects have been written.
719      *
720      * @see ObjectOutputStream#useProtocolVersion
721      * @see ObjectStreamConstants#PROTOCOL_VERSION_1
722      * @see ObjectStreamConstants#PROTOCOL_VERSION_2
723      *
724      * @since JDK 1.2
725      */

726     boolean hasExternalizableBlockDataMode() {
727     return hasExternalizableBlockData;
728     }
729
730     /*
731      * Return the ObjectStreamClass_1_3_1 of the local class this one is based on.
732      */

733     final ObjectStreamClass_1_3_1 localClassDescriptor() {
734     return localClassDesc;
735     }
736
737     /*
738      * Get the Serializability of the class.
739      */

740     boolean isSerializable() {
741     return serializable;
742     }
743
744     /*
745      * Get the externalizability of the class.
746      */

747     boolean isExternalizable() {
748     return externalizable;
749     }
750
751     boolean isNonSerializable() {
752         return ! (externalizable || serializable);
753     }
754
755     /*
756      * Calculate the size of the array needed to store primitive data and the
757      * number of object references to read when reading from the input
758      * stream.
759      */

760     private void computeFieldInfo() {
761     primBytes = 0;
762     objFields = 0;
763
764     for (int i = 0; i < fields.length; i++ ) {
765         switch (fields[i].getTypeCode()) {
766         case 'B':
767         case 'Z':
768             primBytes += 1;
769             break;
770         case 'C':
771         case 'S':
772             primBytes += 2;
773             break;
774
775         case 'I':
776         case 'F':
777             primBytes += 4;
778             break;
779         case 'J':
780         case 'D' :
781             primBytes += 8;
782             break;
783
784         case 'L':
785         case '[':
786             objFields += 1;
787             break;
788         }
789     }
790     }
791
792     private static long computeStructuralUID(ObjectStreamClass_1_3_1 osc, Class JavaDoc cl) {
793     ByteArrayOutputStream JavaDoc devnull = new ByteArrayOutputStream JavaDoc(512);
794         
795     long h = 0;
796     try {
797
798         if ((!java.io.Serializable JavaDoc.class.isAssignableFrom(cl)) ||
799         (cl.isInterface())){
800         return 0;
801         }
802             
803         if (java.io.Externalizable JavaDoc.class.isAssignableFrom(cl)) {
804         return 1;
805         }
806
807         MessageDigest JavaDoc md = MessageDigest.getInstance("SHA");
808         DigestOutputStream JavaDoc mdo = new DigestOutputStream JavaDoc(devnull, md);
809         DataOutputStream JavaDoc data = new DataOutputStream JavaDoc(mdo);
810
811         // Get SUID of parent
812
Class JavaDoc parent = cl.getSuperclass();
813         if ((parent != null))
814         // SerialBug 1; acc. to spec the one for
815
// java.lang.object
816
// should be computed and put
817
// && (parent != java.lang.Object.class))
818
{
819                 //data.writeLong(computeSerialVersionUID(null,parent));
820
data.writeLong(computeStructuralUID(lookup(parent), parent));
821         }
822
823         if (osc.hasWriteObject())
824         data.writeInt(2);
825         else
826         data.writeInt(1);
827
828         /* Sort the field names to get a deterministic order */
829             // Field[] field = ObjectStreamClass_1_3_1.getDeclaredFields(cl);
830

831             ObjectStreamField[] fields = osc.getFields();
832
833             // Must make sure that the Field array we allocate
834
// below is exactly the right size. Bug fix for
835
// 4397133.
836
int numNonNullFields = 0;
837             for (int i = 0; i < fields.length; i++)
838                 if (fields[i].getField() != null)
839                     numNonNullFields++;
840
841             Field JavaDoc [] field = new java.lang.reflect.Field JavaDoc[numNonNullFields];
842             for (int i = 0, fieldNum = 0; i < fields.length; i++) {
843             if (fields[i].getField() != null) {
844                     field[fieldNum++] = fields[i].getField();
845             }
846             }
847
848         if (field.length > 1)
849                 Arrays.sort(field, compareMemberByName);
850
851         for (int i = 0; i < field.length; i++) {
852         Field JavaDoc f = field[i];
853                 
854                 /* Include in the hash all fields except those that are
855                  * transient
856                  */

857         int m = f.getModifiers();
858             //Serial 6
859
//if (Modifier.isTransient(m) || Modifier.isStatic(m))
860
// spec reference 00-01-06.pdf, 1.3.5.6, states non-static
861
// non-transient, public fields are mapped to Java IDL.
862
//
863
// Here's the quote from the first paragraph:
864
// Java non-static non-transient public fields are mapped to
865
// OMG IDL public data members, and other Java fields are
866
// not mapped.
867

868         // if (Modifier.isTransient(m) || Modifier.isStatic(m))
869
// continue;
870

871         data.writeUTF(f.getName());
872         data.writeUTF(getSignature(f.getType()));
873         }
874             
875         /* Compute the hash value for this class.
876          * Use only the first 64 bits of the hash.
877          */

878         data.flush();
879         byte hasharray[] = md.digest();
880         // int minimum = Math.min(8, hasharray.length);
881
// SerialBug 3: SHA computation is wrong; for loop reversed
882
//for (int i = minimum; i > 0; i--)
883
for (int i = 0; i < Math.min(8, hasharray.length); i++) {
884         h += (long)(hasharray[i] & 255) << (i * 8);
885         }
886     } catch (IOException JavaDoc ignore) {
887         /* can't happen, but be deterministic anyway. */
888         h = -1;
889     } catch (NoSuchAlgorithmException JavaDoc complain) {
890         throw new SecurityException JavaDoc(complain.getMessage());
891     }
892     return h;
893     }
894
895     /**
896      * Compute the JVM signature for the class.
897      */

898     static String JavaDoc getSignature(Class JavaDoc clazz) {
899     String JavaDoc type = null;
900     if (clazz.isArray()) {
901         Class JavaDoc cl = clazz;
902         int dimensions = 0;
903         while (cl.isArray()) {
904         dimensions++;
905         cl = cl.getComponentType();
906         }
907         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
908         for (int i = 0; i < dimensions; i++) {
909         sb.append("[");
910         }
911         sb.append(getSignature(cl));
912         type = sb.toString();
913     } else if (clazz.isPrimitive()) {
914         if (clazz == Integer.TYPE) {
915         type = "I";
916         } else if (clazz == Byte.TYPE) {
917         type = "B";
918         } else if (clazz == Long.TYPE) {
919         type = "J";
920         } else if (clazz == Float.TYPE) {
921         type = "F";
922         } else if (clazz == Double.TYPE) {
923         type = "D";
924         } else if (clazz == Short.TYPE) {
925         type = "S";
926         } else if (clazz == Character.TYPE) {
927         type = "C";
928         } else if (clazz == Boolean.TYPE) {
929         type = "Z";
930         } else if (clazz == Void.TYPE) {
931         type = "V";
932         }
933     } else {
934         type = "L" + clazz.getName().replace('.', '/') + ";";
935     }
936     return type;
937     }
938
939     /*
940      * Compute the JVM method descriptor for the method.
941      */

942     static String JavaDoc getSignature(Method JavaDoc meth) {
943     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
944
945     sb.append("(");
946
947     Class JavaDoc[] params = meth.getParameterTypes(); // avoid clone
948
for (int j = 0; j < params.length; j++) {
949         sb.append(getSignature(params[j]));
950     }
951     sb.append(")");
952     sb.append(getSignature(meth.getReturnType()));
953     return sb.toString();
954     }
955
956     /*
957      * Compute the JVM constructor descriptor for the constructor.
958      */

959     static String JavaDoc getSignature(Constructor JavaDoc cons) {
960     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
961
962     sb.append("(");
963
964     Class JavaDoc[] params = cons.getParameterTypes(); // avoid clone
965
for (int j = 0; j < params.length; j++) {
966         sb.append(getSignature(params[j]));
967     }
968     sb.append(")V");
969     return sb.toString();
970     }
971
972     /*
973      * Cache of Class -> ClassDescriptor Mappings.
974      */

975     static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
976
977     /*
978      * findDescriptorFor a Class. This looks in the cache for a
979      * mapping from Class -> ObjectStreamClass mappings. The hashCode
980      * of the Class is used for the lookup since the Class is the key.
981      * The entries are extended from java.lang.ref.SoftReference so the
982      * gc will be able to free them if needed.
983      */

984     private static ObjectStreamClass_1_3_1 findDescriptorFor(Class JavaDoc cl) {
985
986     int hash = cl.hashCode();
987     int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
988     ObjectStreamClassEntry e;
989     ObjectStreamClassEntry prev;
990
991     /* Free any initial entries whose refs have been cleared */
992     while ((e = descriptorFor[index]) != null && e.get() == null) {
993         descriptorFor[index] = e.next;
994     }
995
996     /* Traverse the chain looking for a descriptor with ofClass == cl.
997      * unlink entries that are unresolved.
998      */

999     prev = e;
1000    while (e != null ) {
1001        ObjectStreamClass_1_3_1 desc = (ObjectStreamClass_1_3_1)(e.get());
1002        if (desc == null) {
1003        // This entry has been cleared, unlink it
1004
prev.next = e.next;
1005        } else {
1006        if (desc.ofClass == cl)
1007            return desc;
1008        prev = e;
1009        }
1010        e = e.next;
1011    }
1012    return null;
1013    }
1014
1015    /*
1016     * insertDescriptorFor a Class -> ObjectStreamClass_1_3_1 mapping.
1017     */

1018    private static void insertDescriptorFor(ObjectStreamClass_1_3_1 desc) {
1019    // Make sure not already present
1020
if (findDescriptorFor(desc.ofClass) != null) {
1021        return;
1022    }
1023
1024    int hash = desc.ofClass.hashCode();
1025    int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
1026    ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
1027    e.next = descriptorFor[index];
1028        descriptorFor[index] = e;
1029    }
1030
1031    private static Field JavaDoc[] getDeclaredFields(final Class JavaDoc clz) {
1032        return (Field JavaDoc[]) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
1033            public Object JavaDoc run() {
1034                return clz.getDeclaredFields();
1035            }
1036        });
1037    }
1038
1039
1040    /*
1041     * The name of this descriptor
1042     */

1043    private String JavaDoc name;
1044
1045    /*
1046     * The descriptor of the supertype.
1047     */

1048    private ObjectStreamClass_1_3_1 superclass;
1049
1050    /*
1051     * Flags for Serializable and Externalizable.
1052     */

1053    private boolean serializable;
1054    private boolean externalizable;
1055
1056    /*
1057     * Array of persistent fields of this class, sorted by
1058     * type and name.
1059     */

1060    private ObjectStreamField[] fields;
1061
1062    /*
1063     * Class that is a descriptor for in this virtual machine.
1064     */

1065    private Class JavaDoc ofClass;
1066
1067    /*
1068     * True if descriptor for a proxy class.
1069     */

1070    boolean forProxyClass;
1071
1072
1073    /*
1074     * SerialVersionUID for this class.
1075     */

1076    private long suid = kDefaultUID;
1077    private String JavaDoc suidStr = null;
1078
1079    /*
1080     * Actual (computed) SerialVersionUID for this class.
1081     */

1082    private long actualSuid = kDefaultUID;
1083    private String JavaDoc actualSuidStr = null;
1084
1085    /*
1086     * The total number of bytes of primitive fields.
1087     * The total number of object fields.
1088     */

1089    int primBytes;
1090    int objFields;
1091
1092    /* Internal lock object. */
1093    private Object JavaDoc lock = new Object JavaDoc();
1094
1095    /* True if this class has/had a writeObject method */
1096    private boolean hasWriteObjectMethod;
1097
1098    /* In JDK 1.1, external data was not written in block mode.
1099     * As of JDK 1.2, external data is written in block data mode. This
1100     * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
1101     *
1102     * @since JDK 1.2
1103     */

1104    private boolean hasExternalizableBlockData;
1105    Method JavaDoc writeObjectMethod;
1106    Method JavaDoc readObjectMethod;
1107    private Method JavaDoc writeReplaceObjectMethod;
1108    private Method JavaDoc readResolveObjectMethod;
1109
1110    /*
1111     * ObjectStreamClass_1_3_1 that this one was built from.
1112     */

1113    private ObjectStreamClass_1_3_1 localClassDesc;
1114
1115    /* Get the private static final field for serial version UID */
1116    // private static native long getSerialVersionUIDField(Class cl);
1117

1118    /* The Class Object for java.io.Serializable */
1119    private static Class JavaDoc classSerializable = null;
1120    private static Class JavaDoc classExternalizable = null;
1121
1122    /*
1123     * Resolve java.io.Serializable at load time.
1124     */

1125    static {
1126    try {
1127        classSerializable = Class.forName("java.io.Serializable");
1128        classExternalizable = Class.forName("java.io.Externalizable");
1129    } catch (Throwable JavaDoc e) {
1130        System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
1131    }
1132    }
1133
1134    /** use serialVersionUID from JDK 1.1. for interoperability */
1135    private static final long serialVersionUID = -6120832682080437368L;
1136
1137    /**
1138     * Set serialPersistentFields of a Serializable class to this value to
1139     * denote that the class has no Serializable fields.
1140     */

1141    public static final ObjectStreamField[] NO_FIELDS =
1142        new ObjectStreamField[0];
1143
1144    /*
1145     * Entries held in the Cache of known ObjectStreamClass_1_3_1 objects.
1146     * Entries are chained together with the same hash value (modulo array size).
1147     */

1148    private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
1149
{
1150    ObjectStreamClassEntry(ObjectStreamClass_1_3_1 c) {
1151        //super(c);
1152
this.c = c;
1153    }
1154    ObjectStreamClassEntry next;
1155
1156    public Object JavaDoc get()
1157    {
1158        return c;
1159    }
1160    private ObjectStreamClass_1_3_1 c;
1161    }
1162
1163    /*
1164     * Comparator object for Classes and Interfaces
1165     */

1166    private static Comparator JavaDoc compareClassByName =
1167        new CompareClassByName();
1168
1169    private static class CompareClassByName implements Comparator JavaDoc {
1170    public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1171        Class JavaDoc c1 = (Class JavaDoc)o1;
1172        Class JavaDoc c2 = (Class JavaDoc)o2;
1173        return (c1.getName()).compareTo(c2.getName());
1174    }
1175    }
1176
1177    /*
1178     * Comparator object for Members, Fields, and Methods
1179     */

1180    private static Comparator JavaDoc compareMemberByName =
1181        new CompareMemberByName();
1182
1183    private static class CompareMemberByName implements Comparator JavaDoc {
1184    public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1185        String JavaDoc s1 = ((Member JavaDoc)o1).getName();
1186        String JavaDoc s2 = ((Member JavaDoc)o2).getName();
1187
1188        if (o1 instanceof Method JavaDoc) {
1189        s1 += getSignature((Method JavaDoc)o1);
1190        s2 += getSignature((Method JavaDoc)o2);
1191        } else if (o1 instanceof Constructor JavaDoc) {
1192        s1 += getSignature((Constructor JavaDoc)o1);
1193        s2 += getSignature((Constructor JavaDoc)o2);
1194        }
1195        return s1.compareTo(s2);
1196    }
1197    }
1198
1199    /* It is expensive to recompute a method or constructor signature
1200       many times, so compute it only once using this data structure. */

1201    private static class MethodSignature implements Comparator JavaDoc {
1202    Member JavaDoc member;
1203    String JavaDoc signature; // cached parameter signature
1204

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

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

1209    static MethodSignature[] removePrivateAndSort(Member JavaDoc[] m) {
1210        int numNonPrivate = 0;
1211        for (int i = 0; i < m.length; i++) {
1212        if (! Modifier.isPrivate(m[i].getModifiers())) {
1213            numNonPrivate++;
1214        }
1215        }
1216        MethodSignature[] cm = new MethodSignature[numNonPrivate];
1217        int cmi = 0;
1218        for (int i = 0; i < m.length; i++) {
1219        if (! Modifier.isPrivate(m[i].getModifiers())) {
1220            cm[cmi] = new MethodSignature(m[i]);
1221            cmi++;
1222        }
1223        }
1224        if (cmi > 0)
1225        Arrays.sort(cm, cm[0]);
1226        return cm;
1227    }
1228
1229    /* Assumes that o1 and o2 are either both methods
1230       or both constructors.*/

1231    public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1232        /* Arrays.sort calls compare when o1 and o2 are equal.*/
1233        if (o1 == o2)
1234        return 0;
1235
1236        MethodSignature c1 = (MethodSignature)o1;
1237        MethodSignature c2 = (MethodSignature)o2;
1238
1239        int result;
1240        if (isConstructor()) {
1241        result = c1.signature.compareTo(c2.signature);
1242        } else { // is a Method.
1243
result = c1.member.getName().compareTo(c2.member.getName());
1244        if (result == 0)
1245            result = c1.signature.compareTo(c2.signature);
1246        }
1247        return result;
1248    }
1249
1250    final private boolean isConstructor() {
1251        return member instanceof Constructor JavaDoc;
1252    }
1253    private MethodSignature(Member JavaDoc m) {
1254        member = m;
1255        if (isConstructor()) {
1256        signature = ObjectStreamClass_1_3_1.getSignature((Constructor JavaDoc)m);
1257        } else {
1258        signature = ObjectStreamClass_1_3_1.getSignature((Method JavaDoc)m);
1259        }
1260    }
1261    }
1262}
1263
Popular Tags