Merge from the pain train
[official-gcc.git] / libjava / java / io / ObjectStreamClass.java
bloba5f6ea0be5e510358cb40495dab8757f63b33ce5
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., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 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 void cacheMethods()
491 Method[] methods = forClass().getDeclaredMethods();
492 readObjectMethod = findMethod(methods, "readObject",
493 new Class[] { ObjectInputStream.class },
494 Void.TYPE, true);
495 writeObjectMethod = findMethod(methods, "writeObject",
496 new Class[] { ObjectOutputStream.class },
497 Void.TYPE, true);
498 readResolveMethod = findMethod(methods, "readResolve",
499 new Class[0], Object.class, false);
500 writeReplaceMethod = findMethod(methods, "writeReplace",
501 new Class[0], Object.class, false);
504 private ObjectStreamClass(Class cl)
506 uid = 0;
507 flags = 0;
508 isProxyClass = Proxy.isProxyClass(cl);
510 clazz = cl;
511 cacheMethods();
512 name = cl.getName();
513 setFlags(cl);
514 setFields(cl);
515 // to those class nonserializable, its uid field is 0
516 if ( (Serializable.class).isAssignableFrom(cl) && !isProxyClass)
517 uid = getClassUID(cl);
518 superClass = lookup(cl.getSuperclass());
522 // Sets bits in flags according to features of CL.
523 private void setFlags(Class cl)
525 if ((java.io.Externalizable.class).isAssignableFrom(cl))
526 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
527 else if ((java.io.Serializable.class).isAssignableFrom(cl))
528 // only set this bit if CL is NOT Externalizable
529 flags |= ObjectStreamConstants.SC_SERIALIZABLE;
531 if (writeObjectMethod != null)
532 flags |= ObjectStreamConstants.SC_WRITE_METHOD;
536 // Sets fields to be a sorted array of the serializable fields of
537 // clazz.
538 private void setFields(Class cl)
540 SetAccessibleAction setAccessible = new SetAccessibleAction();
542 if (!isSerializable() || isExternalizable())
544 fields = NO_FIELDS;
545 return;
550 final Field f =
551 cl.getDeclaredField("serialPersistentFields");
552 setAccessible.setMember(f);
553 AccessController.doPrivileged(setAccessible);
554 int modifiers = f.getModifiers();
556 if (Modifier.isStatic(modifiers)
557 && Modifier.isFinal(modifiers)
558 && Modifier.isPrivate(modifiers))
560 fields = getSerialPersistentFields(cl);
561 if (fields != null)
563 Arrays.sort (fields);
564 // Retrieve field reference.
565 for (int i=0; i < fields.length; i++)
569 fields[i].lookupField(cl);
571 catch (NoSuchFieldException _)
573 fields[i].setToSet(false);
577 calculateOffsets();
578 return;
582 catch (NoSuchFieldException ignore)
585 catch (IllegalAccessException ignore)
589 int num_good_fields = 0;
590 Field[] all_fields = cl.getDeclaredFields();
592 int modifiers;
593 // set non-serializable fields to null in all_fields
594 for (int i = 0; i < all_fields.length; i++)
596 modifiers = all_fields[i].getModifiers();
597 if (Modifier.isTransient(modifiers)
598 || Modifier.isStatic(modifiers))
599 all_fields[i] = null;
600 else
601 num_good_fields++;
604 // make a copy of serializable (non-null) fields
605 fields = new ObjectStreamField[ num_good_fields ];
606 for (int from = 0, to = 0; from < all_fields.length; from++)
607 if (all_fields[from] != null)
609 final Field f = all_fields[from];
610 setAccessible.setMember(f);
611 AccessController.doPrivileged(setAccessible);
612 fields[to] = new ObjectStreamField(all_fields[from]);
613 to++;
616 Arrays.sort(fields);
617 // Make sure we don't have any duplicate field names
618 // (Sun JDK 1.4.1. throws an Internal Error as well)
619 for (int i = 1; i < fields.length; i++)
621 if(fields[i - 1].getName().equals(fields[i].getName()))
622 throw new InternalError("Duplicate field " +
623 fields[i].getName() + " in class " + cl.getName());
625 calculateOffsets();
628 // Returns the serial version UID defined by class, or if that
629 // isn't present, calculates value of serial version UID.
630 private long getClassUID(Class cl)
634 // Use getDeclaredField rather than getField, since serialVersionUID
635 // may not be public AND we only want the serialVersionUID of this
636 // class, not a superclass or interface.
637 final Field suid = cl.getDeclaredField("serialVersionUID");
638 SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
639 AccessController.doPrivileged(setAccessible);
640 int modifiers = suid.getModifiers();
642 if (Modifier.isStatic(modifiers)
643 && Modifier.isFinal(modifiers)
644 && suid.getType() == Long.TYPE)
645 return suid.getLong(null);
647 catch (NoSuchFieldException ignore)
650 catch (IllegalAccessException ignore)
654 // cl didn't define serialVersionUID, so we have to compute it
657 MessageDigest md;
658 try
660 md = MessageDigest.getInstance("SHA");
662 catch (NoSuchAlgorithmException e)
664 // If a provider already provides SHA, use it; otherwise, use this.
665 Gnu gnuProvider = new Gnu();
666 Security.addProvider(gnuProvider);
667 md = MessageDigest.getInstance("SHA");
670 DigestOutputStream digest_out =
671 new DigestOutputStream(nullOutputStream, md);
672 DataOutputStream data_out = new DataOutputStream(digest_out);
674 data_out.writeUTF(cl.getName());
676 int modifiers = cl.getModifiers();
677 // just look at interesting bits
678 modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
679 | Modifier.INTERFACE | Modifier.PUBLIC);
680 data_out.writeInt(modifiers);
682 // Pretend that an array has no interfaces, because when array
683 // serialization was defined (JDK 1.1), arrays didn't have it.
684 if (! cl.isArray())
686 Class[] interfaces = cl.getInterfaces();
687 Arrays.sort(interfaces, interfaceComparator);
688 for (int i = 0; i < interfaces.length; i++)
689 data_out.writeUTF(interfaces[i].getName());
692 Field field;
693 Field[] fields = cl.getDeclaredFields();
694 Arrays.sort(fields, memberComparator);
695 for (int i = 0; i < fields.length; i++)
697 field = fields[i];
698 modifiers = field.getModifiers();
699 if (Modifier.isPrivate(modifiers)
700 && (Modifier.isStatic(modifiers)
701 || Modifier.isTransient(modifiers)))
702 continue;
704 data_out.writeUTF(field.getName());
705 data_out.writeInt(modifiers);
706 data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
709 // write class initializer method if present
710 if (VMObjectStreamClass.hasClassInitializer(cl))
712 data_out.writeUTF("<clinit>");
713 data_out.writeInt(Modifier.STATIC);
714 data_out.writeUTF("()V");
717 Constructor constructor;
718 Constructor[] constructors = cl.getDeclaredConstructors();
719 Arrays.sort (constructors, memberComparator);
720 for (int i = 0; i < constructors.length; i++)
722 constructor = constructors[i];
723 modifiers = constructor.getModifiers();
724 if (Modifier.isPrivate(modifiers))
725 continue;
727 data_out.writeUTF("<init>");
728 data_out.writeInt(modifiers);
730 // the replacement of '/' with '.' was needed to make computed
731 // SUID's agree with those computed by JDK
732 data_out.writeUTF
733 (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
736 Method method;
737 Method[] methods = cl.getDeclaredMethods();
738 Arrays.sort(methods, memberComparator);
739 for (int i = 0; i < methods.length; i++)
741 method = methods[i];
742 modifiers = method.getModifiers();
743 if (Modifier.isPrivate(modifiers))
744 continue;
746 data_out.writeUTF(method.getName());
747 data_out.writeInt(modifiers);
749 // the replacement of '/' with '.' was needed to make computed
750 // SUID's agree with those computed by JDK
751 data_out.writeUTF
752 (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
755 data_out.close();
756 byte[] sha = md.digest();
757 long result = 0;
758 int len = sha.length < 8 ? sha.length : 8;
759 for (int i = 0; i < len; i++)
760 result += (long) (sha[i] & 0xFF) << (8 * i);
762 return result;
764 catch (NoSuchAlgorithmException e)
766 throw new RuntimeException
767 ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
768 + cl.getName(), e);
770 catch (IOException ioe)
772 throw new RuntimeException(ioe);
777 * Returns the value of CLAZZ's private static final field named
778 * `serialPersistentFields'. It performs some sanity checks before
779 * returning the real array. Besides, the returned array is a clean
780 * copy of the original. So it can be modified.
782 * @param clazz Class to retrieve 'serialPersistentFields' from.
783 * @return The content of 'serialPersistentFields'.
785 private ObjectStreamField[] getSerialPersistentFields(Class clazz)
786 throws NoSuchFieldException, IllegalAccessException
788 ObjectStreamField[] fieldsArray = null;
789 ObjectStreamField[] o;
791 // Use getDeclaredField rather than getField for the same reason
792 // as above in getDefinedSUID.
793 Field f = clazz.getDeclaredField("serialPersistentFields");
794 f.setAccessible(true);
796 int modifiers = f.getModifiers();
797 if (!(Modifier.isStatic(modifiers) &&
798 Modifier.isFinal(modifiers) &&
799 Modifier.isPrivate(modifiers)))
800 return null;
802 o = (ObjectStreamField[]) f.get(null);
804 if (o == null)
805 return null;
807 fieldsArray = new ObjectStreamField[ o.length ];
808 System.arraycopy(o, 0, fieldsArray, 0, o.length);
810 return fieldsArray;
814 * Returns a new instance of the Class this ObjectStreamClass corresponds
815 * to.
816 * Note that this should only be used for Externalizable classes.
818 * @return A new instance.
820 Externalizable newInstance() throws InvalidClassException
822 synchronized(this)
824 if (constructor == null)
828 final Constructor c = clazz.getConstructor(new Class[0]);
830 AccessController.doPrivileged(new PrivilegedAction()
832 public Object run()
834 c.setAccessible(true);
835 return null;
839 constructor = c;
841 catch(NoSuchMethodException x)
843 throw new InvalidClassException(clazz.getName(),
844 "No public zero-argument constructor");
851 return (Externalizable)constructor.newInstance(null);
853 catch(Exception x)
855 throw (InvalidClassException)
856 new InvalidClassException(clazz.getName(),
857 "Unable to instantiate").initCause(x);
861 public static final ObjectStreamField[] NO_FIELDS = {};
863 private static Hashtable classLookupTable = new Hashtable();
864 private static final NullOutputStream nullOutputStream = new NullOutputStream();
865 private static final Comparator interfaceComparator = new InterfaceComparator();
866 private static final Comparator memberComparator = new MemberComparator();
867 private static final
868 Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
870 private ObjectStreamClass superClass;
871 private Class clazz;
872 private String name;
873 private long uid;
874 private byte flags;
876 // this field is package protected so that ObjectInputStream and
877 // ObjectOutputStream can access it directly
878 ObjectStreamField[] fields;
880 // these are accessed by ObjectIn/OutputStream
881 int primFieldSize = -1; // -1 if not yet calculated
882 int objectFieldCount;
884 Method readObjectMethod;
885 Method readResolveMethod;
886 Method writeReplaceMethod;
887 Method writeObjectMethod;
888 boolean realClassIsSerializable;
889 boolean realClassIsExternalizable;
890 ObjectStreamField[] fieldMapping;
891 Constructor firstNonSerializableParentConstructor;
892 private Constructor constructor; // default constructor for Externalizable
894 boolean isProxyClass = false;
896 // This is probably not necessary because this class is special cased already
897 // but it will avoid showing up as a discrepancy when comparing SUIDs.
898 private static final long serialVersionUID = -6120832682080437368L;
901 // interfaces are compared only by name
902 private static final class InterfaceComparator implements Comparator
904 public int compare(Object o1, Object o2)
906 return ((Class) o1).getName().compareTo(((Class) o2).getName());
911 // Members (Methods and Constructors) are compared first by name,
912 // conflicts are resolved by comparing type signatures
913 private static final class MemberComparator implements Comparator
915 public int compare(Object o1, Object o2)
917 Member m1 = (Member) o1;
918 Member m2 = (Member) o2;
920 int comp = m1.getName().compareTo(m2.getName());
922 if (comp == 0)
923 return TypeSignature.getEncodingOfMember(m1).
924 compareTo(TypeSignature.getEncodingOfMember(m2));
925 else
926 return comp;