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)
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
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
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. */
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
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
74 * @see java.io.Serializable
76 public static ObjectStreamClass
lookup(Class cl
)
80 if (! (Serializable
.class).isAssignableFrom(cl
))
83 return lookupForClassObject(cl
);
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
)
96 ObjectStreamClass osc
= (ObjectStreamClass
) classLookupTable
.get(cl
);
102 osc
= new ObjectStreamClass(cl
);
103 classLookupTable
.put(cl
, 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()
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()
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()
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
);
162 // Can't do binary search since fields is sorted by name and
164 public ObjectStreamField
getField (String name
)
166 for (int i
= 0; i
< fields
.length
; i
++)
167 if (fields
[i
].getName().equals(name
))
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()
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()
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
);
233 return new ObjectStreamClass
[0];
236 Vector oscs
= new Vector();
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
);
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_'
265 ObjectStreamClass(String name
, long uid
, byte flags
,
266 ObjectStreamField
[] fields
)
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
291 long class_uid
= getClassUID(cl
);
296 // Check that the actual UID of the resolved class matches the UID from
298 if (uid
!= class_uid
)
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
;
313 ObjectStreamField
[] exportedFields
= getSerialPersistentFields (clazz
);
315 if (exportedFields
== null)
318 ObjectStreamField
[] newFieldList
= new ObjectStreamField
[exportedFields
.length
+ fields
.length
];
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
);
329 while (i
< fields
.length
&& j
< exportedFields
.length
)
331 int comp
= fields
[i
].compareTo(exportedFields
[j
]);
335 newFieldList
[k
] = fields
[i
];
336 fields
[i
].setPersistent(false);
337 fields
[i
].setToSet(false);
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 _
)
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);
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
];
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
)
404 catch (IllegalAccessException ignore
)
410 void setSuperclass (ObjectStreamClass osc
)
415 void calculateOffsets()
418 ObjectStreamField field
;
420 int fcount
= fields
.length
;
421 for (i
= 0; i
< fcount
; ++ i
)
425 if (! field
.isPrimitive())
428 field
.setOffset(primFieldSize
);
429 switch (field
.getTypeCode())
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
)
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
)))
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
])
481 AccessController
.doPrivileged(new SetAccessibleAction(m
));
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)
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();
519 || Modifier
.isProtected(mods
)
520 || Modifier
.isPublic(mods
)
521 || (! Modifier
.isPrivate(mods
) && inSamePackage(c
, from
)))
523 AccessController
.doPrivileged(new SetAccessibleAction(res
));
527 catch (NoSuchMethodException e
)
535 private void cacheMethods()
537 Method
[] methods
= forClass().getDeclaredMethods();
539 readObjectMethod
= findMethod(methods
, "readObject",
540 new Class
[] { ObjectInputStream
.class },
542 writeObjectMethod
= findMethod(methods
, "writeObject",
543 new Class
[] { ObjectOutputStream
.class },
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
)
556 isProxyClass
= Proxy
.isProxyClass(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
586 private void setFields(Class cl
)
588 SetAccessibleAction setAccessible
= new SetAccessibleAction();
590 if (!isSerializable() || isExternalizable())
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
);
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);
630 catch (NoSuchFieldException ignore
)
633 catch (IllegalAccessException ignore
)
637 int num_good_fields
= 0;
638 Field
[] all_fields
= cl
.getDeclaredFields();
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;
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
]);
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());
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
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.
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());
741 Field
[] fields
= cl
.getDeclaredFields();
742 Arrays
.sort(fields
, memberComparator
);
743 for (int i
= 0; i
< fields
.length
; i
++)
746 modifiers
= field
.getModifiers();
747 if (Modifier
.isPrivate(modifiers
)
748 && (Modifier
.isStatic(modifiers
)
749 || Modifier
.isTransient(modifiers
)))
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
))
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
781 (TypeSignature
.getEncodingOfConstructor(constructor
).replace('/','.'));
785 Method
[] methods
= cl
.getDeclaredMethods();
786 Arrays
.sort(methods
, memberComparator
);
787 for (int i
= 0; i
< methods
.length
; i
++)
790 modifiers
= method
.getModifiers();
791 if (Modifier
.isPrivate(modifiers
))
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
800 (TypeSignature
.getEncodingOfMethod(method
).replace('/', '.'));
804 byte[] sha
= md
.digest();
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
);
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 "
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
)))
850 o
= (ObjectStreamField
[]) f
.get(null);
855 fieldsArray
= new ObjectStreamField
[ o
.length
];
856 System
.arraycopy(o
, 0, fieldsArray
, 0, o
.length
);
862 * Returns a new instance of the Class this ObjectStreamClass corresponds
864 * Note that this should only be used for Externalizable classes.
866 * @return A new instance.
868 Externalizable
newInstance() throws InvalidClassException
872 if (constructor
== null)
876 final Constructor c
= clazz
.getConstructor(new Class
[0]);
878 AccessController
.doPrivileged(new PrivilegedAction()
882 c
.setAccessible(true);
889 catch(NoSuchMethodException x
)
891 throw new InvalidClassException(clazz
.getName(),
892 "No public zero-argument constructor");
899 return (Externalizable
)constructor
.newInstance(null);
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();
916 Class
[] writeMethodArgTypes
= { java
.io
.ObjectOutputStream
.class };
918 private ObjectStreamClass superClass
;
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());
971 return TypeSignature
.getEncodingOfMember(m1
).
972 compareTo(TypeSignature
.getEncodingOfMember(m2
));