Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / java / io / ObjectStreamClass.java
blob975dbfc66d00d7c4517204f0c59c47193435c28d
1 /* ObjectStreamClass.java -- Class used to write class information
2 about serialized objects.
3 Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.io;
42 import gnu.java.io.NullOutputStream;
43 import gnu.java.lang.reflect.TypeSignature;
44 import gnu.java.security.action.SetAccessibleAction;
45 import gnu.java.security.provider.Gnu;
47 import java.lang.reflect.Constructor;
48 import java.lang.reflect.Field;
49 import java.lang.reflect.Member;
50 import java.lang.reflect.Method;
51 import java.lang.reflect.Modifier;
52 import java.lang.reflect.Proxy;
53 import java.security.AccessController;
54 import java.security.DigestOutputStream;
55 import java.security.MessageDigest;
56 import java.security.NoSuchAlgorithmException;
57 import java.security.PrivilegedAction;
58 import java.security.Security;
59 import java.util.Arrays;
60 import java.util.Comparator;
61 import java.util.Hashtable;
62 import java.util.Vector;
64 public class ObjectStreamClass implements Serializable
66 /**
67 * Returns the <code>ObjectStreamClass</code> for <code>cl</code>.
68 * If <code>cl</code> is null, or is not <code>Serializable</code>,
69 * null is returned. <code>ObjectStreamClass</code>'s are memorized;
70 * later calls to this method with the same class will return the
71 * same <code>ObjectStreamClass</code> object and no recalculation
72 * will be done.
74 * @see java.io.Serializable
76 public static ObjectStreamClass lookup(Class cl)
78 if (cl == null)
79 return null;
80 if (! (Serializable.class).isAssignableFrom(cl))
81 return null;
83 return lookupForClassObject(cl);
86 /**
87 * This lookup for internal use by ObjectOutputStream. Suppose
88 * we have a java.lang.Class object C for class A, though A is not
89 * serializable, but it's okay to serialize C.
91 static ObjectStreamClass lookupForClassObject(Class cl)
93 if (cl == null)
94 return null;
96 ObjectStreamClass osc = (ObjectStreamClass) classLookupTable.get(cl);
98 if (osc != null)
99 return osc;
100 else
102 osc = new ObjectStreamClass(cl);
103 classLookupTable.put(cl, osc);
104 return osc;
109 * Returns the name of the class that this
110 * <code>ObjectStreamClass</code> represents.
112 * @return the name of the class.
114 public String getName()
116 return name;
120 * Returns the class that this <code>ObjectStreamClass</code>
121 * represents. Null could be returned if this
122 * <code>ObjectStreamClass</code> was read from an
123 * <code>ObjectInputStream</code> and the class it represents cannot
124 * be found or loaded.
126 * @see java.io.ObjectInputStream
128 public Class forClass()
130 return clazz;
134 * Returns the serial version stream-unique identifier for the class
135 * represented by this <code>ObjectStreamClass</code>. This SUID is
136 * either defined by the class as <code>static final long
137 * serialVersionUID</code> or is calculated as specified in
138 * Javasoft's "Object Serialization Specification" XXX: add reference
140 * @return the serial version UID.
142 public long getSerialVersionUID()
144 return uid;
148 * Returns the serializable (non-static and non-transient) Fields
149 * of the class represented by this ObjectStreamClass. The Fields
150 * are sorted by name.
152 * @return the fields.
154 public ObjectStreamField[] getFields()
156 ObjectStreamField[] copy = new ObjectStreamField[ fields.length ];
157 System.arraycopy(fields, 0, copy, 0, fields.length);
158 return copy;
161 // XXX doc
162 // Can't do binary search since fields is sorted by name and
163 // primitiveness.
164 public ObjectStreamField getField (String name)
166 for (int i = 0; i < fields.length; i++)
167 if (fields[i].getName().equals(name))
168 return fields[i];
169 return null;
173 * Returns a textual representation of this
174 * <code>ObjectStreamClass</code> object including the name of the
175 * class it represents as well as that class's serial version
176 * stream-unique identifier.
178 * @see #getSerialVersionUID()
179 * @see #getName()
181 public String toString()
183 return "java.io.ObjectStreamClass< " + name + ", " + uid + " >";
186 // Returns true iff the class that this ObjectStreamClass represents
187 // has the following method:
189 // private void writeObject (ObjectOutputStream)
191 // This method is used by the class to override default
192 // serialization behavior.
193 boolean hasWriteMethod()
195 return (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0;
198 // Returns true iff the class that this ObjectStreamClass represents
199 // implements Serializable but does *not* implement Externalizable.
200 boolean isSerializable()
202 return (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
206 // Returns true iff the class that this ObjectStreamClass represents
207 // implements Externalizable.
208 boolean isExternalizable()
210 return (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
214 // Returns the <code>ObjectStreamClass</code> that represents the
215 // class that is the superclass of the class this
216 // <code>ObjectStreamClass</code> represents. If the superclass is
217 // not Serializable, null is returned.
218 ObjectStreamClass getSuper()
220 return superClass;
224 // returns an array of ObjectStreamClasses that represent the super
225 // classes of CLAZZ and CLAZZ itself in order from most super to
226 // CLAZZ. ObjectStreamClass[0] is the highest superclass of CLAZZ
227 // that is serializable.
228 static ObjectStreamClass[] getObjectStreamClasses(Class clazz)
230 ObjectStreamClass osc = ObjectStreamClass.lookup(clazz);
232 if (osc == null)
233 return new ObjectStreamClass[0];
234 else
236 Vector oscs = new Vector();
238 while (osc != null)
240 oscs.addElement (osc);
241 osc = osc.getSuper();
244 int count = oscs.size();
245 ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[ count ];
247 for (int i = count - 1; i >= 0; i--)
248 sorted_oscs[ count - i - 1 ] = (ObjectStreamClass) oscs.elementAt(i);
250 return sorted_oscs;
255 // Returns an integer that consists of bit-flags that indicate
256 // properties of the class represented by this ObjectStreamClass.
257 // The bit-flags that could be present are those defined in
258 // ObjectStreamConstants that begin with `SC_'
259 int getFlags()
261 return flags;
265 ObjectStreamClass(String name, long uid, byte flags,
266 ObjectStreamField[] fields)
268 this.name = name;
269 this.uid = uid;
270 this.flags = flags;
271 this.fields = fields;
275 * This method builds the internal description corresponding to a Java Class.
276 * As the constructor only assign a name to the current ObjectStreamClass instance,
277 * that method sets the serial UID, chose the fields which will be serialized,
278 * and compute the position of the fields in the serialized stream.
280 * @param cl The Java class which is used as a reference for building the descriptor.
281 * @param superClass The descriptor of the super class for this class descriptor.
282 * @throws InvalidClassException if an incompatibility between computed UID and
283 * already set UID is found.
285 void setClass(Class cl, ObjectStreamClass superClass) throws InvalidClassException
287 this.clazz = cl;
289 cacheMethods();
291 long class_uid = getClassUID(cl);
292 if (uid == 0)
293 uid = class_uid;
294 else
296 // Check that the actual UID of the resolved class matches the UID from
297 // the stream.
298 if (uid != class_uid)
300 String msg = cl +
301 ": Local class not compatible: stream serialVersionUID="
302 + uid + ", local serialVersionUID=" + class_uid;
303 throw new InvalidClassException (msg);
307 isProxyClass = clazz != null && Proxy.isProxyClass(clazz);
308 this.superClass = superClass;
309 calculateOffsets();
313 ObjectStreamField[] exportedFields = getSerialPersistentFields (clazz);
315 if (exportedFields == null)
316 return;
318 ObjectStreamField[] newFieldList = new ObjectStreamField[exportedFields.length + fields.length];
319 int i, j, k;
321 /* We now check the import fields against the exported fields.
322 * There should not be contradiction (e.g. int x and String x)
323 * but extra virtual fields can be added to the class.
326 Arrays.sort(exportedFields);
328 i = 0; j = 0; k = 0;
329 while (i < fields.length && j < exportedFields.length)
331 int comp = fields[i].compareTo(exportedFields[j]);
333 if (comp < 0)
335 newFieldList[k] = fields[i];
336 fields[i].setPersistent(false);
337 fields[i].setToSet(false);
338 i++;
340 else if (comp > 0)
342 /* field not found in imported fields. We add it
343 * in the list of supported fields.
345 newFieldList[k] = exportedFields[j];
346 newFieldList[k].setPersistent(true);
347 newFieldList[k].setToSet(false);
350 newFieldList[k].lookupField(clazz);
351 newFieldList[k].checkFieldType();
353 catch (NoSuchFieldException _)
356 j++;
358 else
362 exportedFields[j].lookupField(clazz);
363 exportedFields[j].checkFieldType();
365 catch (NoSuchFieldException _)
369 if (!fields[i].getType().equals(exportedFields[j].getType()))
370 throw new InvalidClassException
371 ("serialPersistentFields must be compatible with" +
372 " imported fields (about " + fields[i].getName() + ")");
373 newFieldList[k] = fields[i];
374 fields[i].setPersistent(true);
375 i++;
376 j++;
378 k++;
381 if (i < fields.length)
382 for (;i<fields.length;i++,k++)
384 fields[i].setPersistent(false);
385 fields[i].setToSet(false);
386 newFieldList[k] = fields[i];
388 else
389 if (j < exportedFields.length)
390 for (;j<exportedFields.length;j++,k++)
392 exportedFields[j].setPersistent(true);
393 exportedFields[j].setToSet(false);
394 newFieldList[k] = exportedFields[j];
397 fields = new ObjectStreamField[k];
398 System.arraycopy(newFieldList, 0, fields, 0, k);
400 catch (NoSuchFieldException ignore)
402 return;
404 catch (IllegalAccessException ignore)
406 return;
410 void setSuperclass (ObjectStreamClass osc)
412 superClass = osc;
415 void calculateOffsets()
417 int i;
418 ObjectStreamField field;
419 primFieldSize = 0;
420 int fcount = fields.length;
421 for (i = 0; i < fcount; ++ i)
423 field = fields[i];
425 if (! field.isPrimitive())
426 break;
428 field.setOffset(primFieldSize);
429 switch (field.getTypeCode())
431 case 'B':
432 case 'Z':
433 ++ primFieldSize;
434 break;
435 case 'C':
436 case 'S':
437 primFieldSize += 2;
438 break;
439 case 'I':
440 case 'F':
441 primFieldSize += 4;
442 break;
443 case 'D':
444 case 'J':
445 primFieldSize += 8;
446 break;
450 for (objectFieldCount = 0; i < fcount; ++ i)
451 fields[i].setOffset(objectFieldCount++);
454 private Method findMethod(Method[] methods, String name, Class[] params,
455 Class returnType, boolean mustBePrivate)
457 outer:
458 for (int i = 0; i < methods.length; i++)
460 final Method m = methods[i];
461 int mods = m.getModifiers();
462 if (Modifier.isStatic(mods)
463 || (mustBePrivate && !Modifier.isPrivate(mods)))
465 continue;
468 if (m.getName().equals(name)
469 && m.getReturnType() == returnType)
471 Class[] mp = m.getParameterTypes();
472 if (mp.length == params.length)
474 for (int j = 0; j < mp.length; j++)
476 if (mp[j] != params[j])
478 continue outer;
481 AccessController.doPrivileged(new SetAccessibleAction(m));
482 return m;
486 return null;
489 private static boolean inSamePackage(Class c1, Class c2)
491 String name1 = c1.getName();
492 String name2 = c2.getName();
494 int id1 = name1.lastIndexOf('.');
495 int id2 = name2.lastIndexOf('.');
497 // Handle the default package
498 if (id1 == -1 || id2 == -1)
499 return id1 == id2;
501 String package1 = name1.substring(0, id1);
502 String package2 = name2.substring(0, id2);
504 return package1.equals(package2);
507 final static Class[] noArgs = new Class[0];
509 private static Method findAccessibleMethod(String name, Class from)
511 for (Class c = from; c != null; c = c.getSuperclass())
515 Method res = c.getDeclaredMethod(name, noArgs);
516 int mods = res.getModifiers();
518 if (c == from
519 || Modifier.isProtected(mods)
520 || Modifier.isPublic(mods)
521 || (! Modifier.isPrivate(mods) && inSamePackage(c, from)))
523 AccessController.doPrivileged(new SetAccessibleAction(res));
524 return res;
527 catch (NoSuchMethodException e)
532 return null;
535 private void cacheMethods()
537 Method[] methods = forClass().getDeclaredMethods();
539 readObjectMethod = findMethod(methods, "readObject",
540 new Class[] { ObjectInputStream.class },
541 Void.TYPE, true);
542 writeObjectMethod = findMethod(methods, "writeObject",
543 new Class[] { ObjectOutputStream.class },
544 Void.TYPE, true);
546 // readResolve and writeReplace can be in parent classes, as long as they
547 // are accessible from this class.
548 readResolveMethod = findAccessibleMethod("readResolve", forClass());
549 writeReplaceMethod = findAccessibleMethod("writeReplace", forClass());
552 private ObjectStreamClass(Class cl)
554 uid = 0;
555 flags = 0;
556 isProxyClass = Proxy.isProxyClass(cl);
558 clazz = cl;
559 cacheMethods();
560 name = cl.getName();
561 setFlags(cl);
562 setFields(cl);
563 // to those class nonserializable, its uid field is 0
564 if ( (Serializable.class).isAssignableFrom(cl) && !isProxyClass)
565 uid = getClassUID(cl);
566 superClass = lookup(cl.getSuperclass());
570 // Sets bits in flags according to features of CL.
571 private void setFlags(Class cl)
573 if ((java.io.Externalizable.class).isAssignableFrom(cl))
574 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
575 else if ((java.io.Serializable.class).isAssignableFrom(cl))
576 // only set this bit if CL is NOT Externalizable
577 flags |= ObjectStreamConstants.SC_SERIALIZABLE;
579 if (writeObjectMethod != null)
580 flags |= ObjectStreamConstants.SC_WRITE_METHOD;
584 // Sets fields to be a sorted array of the serializable fields of
585 // clazz.
586 private void setFields(Class cl)
588 SetAccessibleAction setAccessible = new SetAccessibleAction();
590 if (!isSerializable() || isExternalizable())
592 fields = NO_FIELDS;
593 return;
598 final Field f =
599 cl.getDeclaredField("serialPersistentFields");
600 setAccessible.setMember(f);
601 AccessController.doPrivileged(setAccessible);
602 int modifiers = f.getModifiers();
604 if (Modifier.isStatic(modifiers)
605 && Modifier.isFinal(modifiers)
606 && Modifier.isPrivate(modifiers))
608 fields = getSerialPersistentFields(cl);
609 if (fields != null)
611 Arrays.sort (fields);
612 // Retrieve field reference.
613 for (int i=0; i < fields.length; i++)
617 fields[i].lookupField(cl);
619 catch (NoSuchFieldException _)
621 fields[i].setToSet(false);
625 calculateOffsets();
626 return;
630 catch (NoSuchFieldException ignore)
633 catch (IllegalAccessException ignore)
637 int num_good_fields = 0;
638 Field[] all_fields = cl.getDeclaredFields();
640 int modifiers;
641 // set non-serializable fields to null in all_fields
642 for (int i = 0; i < all_fields.length; i++)
644 modifiers = all_fields[i].getModifiers();
645 if (Modifier.isTransient(modifiers)
646 || Modifier.isStatic(modifiers))
647 all_fields[i] = null;
648 else
649 num_good_fields++;
652 // make a copy of serializable (non-null) fields
653 fields = new ObjectStreamField[ num_good_fields ];
654 for (int from = 0, to = 0; from < all_fields.length; from++)
655 if (all_fields[from] != null)
657 final Field f = all_fields[from];
658 setAccessible.setMember(f);
659 AccessController.doPrivileged(setAccessible);
660 fields[to] = new ObjectStreamField(all_fields[from]);
661 to++;
664 Arrays.sort(fields);
665 // Make sure we don't have any duplicate field names
666 // (Sun JDK 1.4.1. throws an Internal Error as well)
667 for (int i = 1; i < fields.length; i++)
669 if(fields[i - 1].getName().equals(fields[i].getName()))
670 throw new InternalError("Duplicate field " +
671 fields[i].getName() + " in class " + cl.getName());
673 calculateOffsets();
676 // Returns the serial version UID defined by class, or if that
677 // isn't present, calculates value of serial version UID.
678 private long getClassUID(Class cl)
682 // Use getDeclaredField rather than getField, since serialVersionUID
683 // may not be public AND we only want the serialVersionUID of this
684 // class, not a superclass or interface.
685 final Field suid = cl.getDeclaredField("serialVersionUID");
686 SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
687 AccessController.doPrivileged(setAccessible);
688 int modifiers = suid.getModifiers();
690 if (Modifier.isStatic(modifiers)
691 && Modifier.isFinal(modifiers)
692 && suid.getType() == Long.TYPE)
693 return suid.getLong(null);
695 catch (NoSuchFieldException ignore)
698 catch (IllegalAccessException ignore)
702 // cl didn't define serialVersionUID, so we have to compute it
705 MessageDigest md;
706 try
708 md = MessageDigest.getInstance("SHA");
710 catch (NoSuchAlgorithmException e)
712 // If a provider already provides SHA, use it; otherwise, use this.
713 Gnu gnuProvider = new Gnu();
714 Security.addProvider(gnuProvider);
715 md = MessageDigest.getInstance("SHA");
718 DigestOutputStream digest_out =
719 new DigestOutputStream(nullOutputStream, md);
720 DataOutputStream data_out = new DataOutputStream(digest_out);
722 data_out.writeUTF(cl.getName());
724 int modifiers = cl.getModifiers();
725 // just look at interesting bits
726 modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
727 | Modifier.INTERFACE | Modifier.PUBLIC);
728 data_out.writeInt(modifiers);
730 // Pretend that an array has no interfaces, because when array
731 // serialization was defined (JDK 1.1), arrays didn't have it.
732 if (! cl.isArray())
734 Class[] interfaces = cl.getInterfaces();
735 Arrays.sort(interfaces, interfaceComparator);
736 for (int i = 0; i < interfaces.length; i++)
737 data_out.writeUTF(interfaces[i].getName());
740 Field field;
741 Field[] fields = cl.getDeclaredFields();
742 Arrays.sort(fields, memberComparator);
743 for (int i = 0; i < fields.length; i++)
745 field = fields[i];
746 modifiers = field.getModifiers();
747 if (Modifier.isPrivate(modifiers)
748 && (Modifier.isStatic(modifiers)
749 || Modifier.isTransient(modifiers)))
750 continue;
752 data_out.writeUTF(field.getName());
753 data_out.writeInt(modifiers);
754 data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
757 // write class initializer method if present
758 if (VMObjectStreamClass.hasClassInitializer(cl))
760 data_out.writeUTF("<clinit>");
761 data_out.writeInt(Modifier.STATIC);
762 data_out.writeUTF("()V");
765 Constructor constructor;
766 Constructor[] constructors = cl.getDeclaredConstructors();
767 Arrays.sort (constructors, memberComparator);
768 for (int i = 0; i < constructors.length; i++)
770 constructor = constructors[i];
771 modifiers = constructor.getModifiers();
772 if (Modifier.isPrivate(modifiers))
773 continue;
775 data_out.writeUTF("<init>");
776 data_out.writeInt(modifiers);
778 // the replacement of '/' with '.' was needed to make computed
779 // SUID's agree with those computed by JDK
780 data_out.writeUTF
781 (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
784 Method method;
785 Method[] methods = cl.getDeclaredMethods();
786 Arrays.sort(methods, memberComparator);
787 for (int i = 0; i < methods.length; i++)
789 method = methods[i];
790 modifiers = method.getModifiers();
791 if (Modifier.isPrivate(modifiers))
792 continue;
794 data_out.writeUTF(method.getName());
795 data_out.writeInt(modifiers);
797 // the replacement of '/' with '.' was needed to make computed
798 // SUID's agree with those computed by JDK
799 data_out.writeUTF
800 (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
803 data_out.close();
804 byte[] sha = md.digest();
805 long result = 0;
806 int len = sha.length < 8 ? sha.length : 8;
807 for (int i = 0; i < len; i++)
808 result += (long) (sha[i] & 0xFF) << (8 * i);
810 return result;
812 catch (NoSuchAlgorithmException e)
814 throw new RuntimeException
815 ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
816 + cl.getName(), e);
818 catch (IOException ioe)
820 throw new RuntimeException(ioe);
825 * Returns the value of CLAZZ's private static final field named
826 * `serialPersistentFields'. It performs some sanity checks before
827 * returning the real array. Besides, the returned array is a clean
828 * copy of the original. So it can be modified.
830 * @param clazz Class to retrieve 'serialPersistentFields' from.
831 * @return The content of 'serialPersistentFields'.
833 private ObjectStreamField[] getSerialPersistentFields(Class clazz)
834 throws NoSuchFieldException, IllegalAccessException
836 ObjectStreamField[] fieldsArray = null;
837 ObjectStreamField[] o;
839 // Use getDeclaredField rather than getField for the same reason
840 // as above in getDefinedSUID.
841 Field f = clazz.getDeclaredField("serialPersistentFields");
842 f.setAccessible(true);
844 int modifiers = f.getModifiers();
845 if (!(Modifier.isStatic(modifiers) &&
846 Modifier.isFinal(modifiers) &&
847 Modifier.isPrivate(modifiers)))
848 return null;
850 o = (ObjectStreamField[]) f.get(null);
852 if (o == null)
853 return null;
855 fieldsArray = new ObjectStreamField[ o.length ];
856 System.arraycopy(o, 0, fieldsArray, 0, o.length);
858 return fieldsArray;
862 * Returns a new instance of the Class this ObjectStreamClass corresponds
863 * to.
864 * Note that this should only be used for Externalizable classes.
866 * @return A new instance.
868 Externalizable newInstance() throws InvalidClassException
870 synchronized(this)
872 if (constructor == null)
876 final Constructor c = clazz.getConstructor(new Class[0]);
878 AccessController.doPrivileged(new PrivilegedAction()
880 public Object run()
882 c.setAccessible(true);
883 return null;
887 constructor = c;
889 catch(NoSuchMethodException x)
891 throw new InvalidClassException(clazz.getName(),
892 "No public zero-argument constructor");
899 return (Externalizable)constructor.newInstance(null);
901 catch(Exception x)
903 throw (InvalidClassException)
904 new InvalidClassException(clazz.getName(),
905 "Unable to instantiate").initCause(x);
909 public static final ObjectStreamField[] NO_FIELDS = {};
911 private static Hashtable classLookupTable = new Hashtable();
912 private static final NullOutputStream nullOutputStream = new NullOutputStream();
913 private static final Comparator interfaceComparator = new InterfaceComparator();
914 private static final Comparator memberComparator = new MemberComparator();
915 private static final
916 Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
918 private ObjectStreamClass superClass;
919 private Class clazz;
920 private String name;
921 private long uid;
922 private byte flags;
924 // this field is package protected so that ObjectInputStream and
925 // ObjectOutputStream can access it directly
926 ObjectStreamField[] fields;
928 // these are accessed by ObjectIn/OutputStream
929 int primFieldSize = -1; // -1 if not yet calculated
930 int objectFieldCount;
932 Method readObjectMethod;
933 Method readResolveMethod;
934 Method writeReplaceMethod;
935 Method writeObjectMethod;
936 boolean realClassIsSerializable;
937 boolean realClassIsExternalizable;
938 ObjectStreamField[] fieldMapping;
939 Constructor firstNonSerializableParentConstructor;
940 private Constructor constructor; // default constructor for Externalizable
942 boolean isProxyClass = false;
944 // This is probably not necessary because this class is special cased already
945 // but it will avoid showing up as a discrepancy when comparing SUIDs.
946 private static final long serialVersionUID = -6120832682080437368L;
949 // interfaces are compared only by name
950 private static final class InterfaceComparator implements Comparator
952 public int compare(Object o1, Object o2)
954 return ((Class) o1).getName().compareTo(((Class) o2).getName());
959 // Members (Methods and Constructors) are compared first by name,
960 // conflicts are resolved by comparing type signatures
961 private static final class MemberComparator implements Comparator
963 public int compare(Object o1, Object o2)
965 Member m1 = (Member) o1;
966 Member m2 = (Member) o2;
968 int comp = m1.getName().compareTo(m2.getName());
970 if (comp == 0)
971 return TypeSignature.getEncodingOfMember(m1).
972 compareTo(TypeSignature.getEncodingOfMember(m2));
973 else
974 return comp;