2 Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.java.rmi.rmic;
41 import java.io.FileWriter;
42 import java.io.PrintWriter;
43 import java.io.IOException;
44 import java.lang.reflect.Method;
45 import java.lang.reflect.Modifier;
46 import java.rmi.RemoteException;
47 import java.util.HashSet;
48 import java.util.Iterator;
49 import java.util.Arrays;
52 import gnu.java.rmi.server.RMIHashes;
56 private String[] args;
58 private Exception exception;
60 private boolean keep = false;
61 private boolean need11Stubs = true;
62 private boolean need12Stubs = true;
63 private boolean compile = true;
64 private boolean verbose;
65 private String destination;
67 private PrintWriter out;
68 private TabbedWriter ctrl;
71 private String classname;
72 private String fullclassname;
73 private MethodRef[] remotemethods;
74 private String stubname;
75 private String skelname;
76 private int errorCount = 0;
78 private Class mRemoteInterface;
79 public RMIC(String[] a) {
83 public static void main(String args[]) {
84 RMIC r = new RMIC(args);
85 if (r.run() == false) {
86 Exception exception = r.getException();
87 if (exception != null) {
88 exception.printStackTrace();
96 public boolean run() {
98 if (next >= args.length) {
99 error("no class names found");
101 for (int i = next; i < args.length; i++) {
104 System.out.println("[Processing class " + args[i] + ".class]");
106 processClass(args[i].replace(File.separatorChar, '.'));
108 catch (Exception e) {
116 private boolean processClass(String classname) throws Exception {
118 analyzeClass(classname);
127 compile(stubname.replace('.', File.separatorChar) + ".java");
129 compile(skelname.replace('.', File.separatorChar) + ".java");
133 (new File(stubname.replace('.', File.separatorChar) + ".java")).delete();
135 (new File(skelname.replace('.', File.separatorChar) + ".java")).delete();
141 private void analyzeClass(String cname) throws Exception {
143 System.out.println("[analyze class "+cname+"]");
145 int p = cname.lastIndexOf('.');
147 classname = cname.substring(p+1);
152 fullclassname = cname;
155 HashSet rmeths = new HashSet();
158 // get the remote interface
159 mRemoteInterface = getRemoteInterface(clazz);
160 if(mRemoteInterface == null)
163 System.out.println("[implements "+mRemoteInterface.getName()+"]");
166 // check if the methods of the remote interface declare RemoteExceptions
167 Method[] meths = mRemoteInterface.getDeclaredMethods();
168 for (int i = 0; i < meths.length; i++) {
169 Class[] exceptions = meths[i].getExceptionTypes();
171 for(;index < exceptions.length; index++){
172 if(exceptions[index].equals(RemoteException.class)){
176 if (index < exceptions.length) {
177 rmeths.add(meths[i]);
179 logError("Method "+meths[i]+" does not throw a java.rmi.RemoteException");
184 // Convert into a MethodRef array and sort them
185 remotemethods = new MethodRef[rmeths.size()];
187 for (Iterator i = rmeths.iterator(); i.hasNext(); ) {
188 remotemethods[c++] = new MethodRef((Method)i.next());
190 Arrays.sort(remotemethods);
193 public Exception getException() {
197 private void findClass() throws ClassNotFoundException {
198 clazz = Class.forName(fullclassname, true, ClassLoader.getSystemClassLoader());
201 private void generateStub() throws IOException {
202 stubname = fullclassname + "_Stub";
203 String stubclassname = classname + "_Stub";
204 ctrl = new TabbedWriter(new FileWriter((destination == null ? "" : destination + File.separator)
205 + stubname.replace('.', File.separatorChar)
207 out = new PrintWriter(ctrl);
210 System.out.println("[Generating class " + stubname + ".java]");
213 out.println("// Stub class generated by rmic - DO NOT EDIT!");
215 if (fullclassname != classname) {
216 String pname = fullclassname.substring(0, fullclassname.lastIndexOf('.'));
217 out.println("package " + pname + ";");
221 out.print("public final class " + stubclassname);
223 out.println("extends java.rmi.server.RemoteStub");
225 // Output interfaces we implement
226 out.print("implements ");
227 /* Scan implemented interfaces, and only print remote interfaces. */
228 Class[] ifaces = clazz.getInterfaces();
229 Set remoteIfaces = new HashSet();
230 for (int i = 0; i < ifaces.length; i++) {
231 Class iface = ifaces[i];
232 if (java.rmi.Remote.class.isAssignableFrom(iface)) {
233 remoteIfaces.add(iface);
236 Iterator iter = remoteIfaces.iterator();
237 while (iter.hasNext()) {
238 /* Print remote interface. */
239 Class iface = (Class) iter.next();
240 out.print(iface.getName());
242 /* Print ", " if more remote interfaces follow. */
243 if (iter.hasNext()) {
253 out.println("private static final long serialVersionUID = 2L;");
257 // InterfaceHash - don't know how to calculate this - XXX
259 out.println("private static final long interfaceHash = " + RMIHashes.getInterfaceHash(clazz) + "L;");
262 out.println("private static boolean useNewInvoke;");
267 out.print("private static final java.rmi.server.Operation[] operations = {");
270 for (int i = 0; i < remotemethods.length; i++) {
271 Method m = remotemethods[i].meth;
272 out.print("new java.rmi.server.Operation(\"");
273 out.print(getPrettyName(m.getReturnType()) + " ");
274 out.print(m.getName() + "(");
276 Class[] sig = m.getParameterTypes();
277 for (int j = 0; j < sig.length; j++) {
278 out.print(getPrettyName(sig[j]));
279 if (j+1 < sig.length) {
284 if (i + 1 < remotemethods.length) {
293 // Set of method references.
295 for (int i = 0; i < remotemethods.length; i++) {
296 Method m = remotemethods[i].meth;
297 out.println("private static java.lang.reflect.Method $method_" + m.getName() + "_" + i + ";");
300 // Initialize the methods references.
302 out.print("static {");
309 out.println("java.rmi.server.RemoteRef.class.getMethod(\"invoke\", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class });");
310 out.println("useNewInvoke = true;");
313 for (int i = 0; i < remotemethods.length; i++) {
314 Method m = remotemethods[i].meth;
315 out.print("$method_" + m.getName() + "_" + i + " = ");
316 out.print(mRemoteInterface.getName() + ".class.getMethod(\"" + m.getName() + "\"");
317 out.print(", new java.lang.Class[] {");
319 Class[] sig = m.getParameterTypes();
320 for (int j = 0; j < sig.length; j++) {
321 out.print(getPrettyName(sig[j]) + ".class");
322 if (j+1 < sig.length) {
330 out.print("catch (java.lang.NoSuchMethodException e) {");
333 out.print("useNewInvoke = false;");
336 out.print("throw new java.lang.NoSuchMethodError(\"stub class initialization failed\");");
349 out.print("public " + stubclassname + "() {");
351 out.print("super();");
357 out.print("public " + stubclassname + "(java.rmi.server.RemoteRef ref) {");
359 out.print("super(ref);");
364 // Method implementations
365 for (int i = 0; i < remotemethods.length; i++) {
366 Method m = remotemethods[i].meth;
367 Class[] sig = m.getParameterTypes();
368 Class returntype = m.getReturnType();
369 Class[] except = sortExceptions(m.getExceptionTypes());
372 out.print("public " + getPrettyName(returntype) + " " + m.getName() + "(");
373 for (int j = 0; j < sig.length; j++) {
374 out.print(getPrettyName(sig[j]));
375 out.print(" $param_" + j);
376 if (j+1 < sig.length) {
381 out.print("throws ");
382 for (int j = 0; j < except.length; j++) {
383 out.print(getPrettyName(except[j]));
384 if (j+1 < except.length) {
396 out.print("if (useNewInvoke) {");
399 if (returntype != Void.TYPE) {
400 out.print("java.lang.Object $result = ");
402 out.print("ref.invoke(this, $method_" + m.getName() + "_" + i + ", ");
403 if (sig.length == 0) {
407 out.print("new java.lang.Object[] {");
408 for (int j = 0; j < sig.length; j++) {
409 if (sig[j] == Boolean.TYPE) {
410 out.print("new java.lang.Boolean($param_" + j + ")");
412 else if (sig[j] == Byte.TYPE) {
413 out.print("new java.lang.Byte($param_" + j + ")");
415 else if (sig[j] == Character.TYPE) {
416 out.print("new java.lang.Character($param_" + j + ")");
418 else if (sig[j] == Short.TYPE) {
419 out.print("new java.lang.Short($param_" + j + ")");
421 else if (sig[j] == Integer.TYPE) {
422 out.print("new java.lang.Integer($param_" + j + ")");
424 else if (sig[j] == Long.TYPE) {
425 out.print("new java.lang.Long($param_" + j + ")");
427 else if (sig[j] == Float.TYPE) {
428 out.print("new java.lang.Float($param_" + j + ")");
430 else if (sig[j] == Double.TYPE) {
431 out.print("new java.lang.Double($param_" + j + ")");
434 out.print("$param_" + j);
436 if (j+1 < sig.length) {
442 out.print(Long.toString(remotemethods[i].hash) + "L");
445 if (returntype != Void.TYPE) {
447 out.print("return (");
448 if (returntype == Boolean.TYPE) {
449 out.print("((java.lang.Boolean)$result).booleanValue()");
451 else if (returntype == Byte.TYPE) {
452 out.print("((java.lang.Byte)$result).byteValue()");
454 else if (returntype == Character.TYPE) {
455 out.print("((java.lang.Character)$result).charValue()");
457 else if (returntype == Short.TYPE) {
458 out.print("((java.lang.Short)$result).shortValue()");
460 else if (returntype == Integer.TYPE) {
461 out.print("((java.lang.Integer)$result).intValue()");
463 else if (returntype == Long.TYPE) {
464 out.print("((java.lang.Long)$result).longValue()");
466 else if (returntype == Float.TYPE) {
467 out.print("((java.lang.Float)$result).floatValue()");
469 else if (returntype == Double.TYPE) {
470 out.print("((java.lang.Double)$result).doubleValue()");
473 out.print("(" + getPrettyName(returntype) + ")$result");
487 out.println("java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, " + i + ", interfaceHash);");
490 out.print("java.io.ObjectOutput out = call.getOutputStream();");
491 for (int j = 0; j < sig.length; j++) {
493 if (sig[j] == Boolean.TYPE) {
494 out.print("out.writeBoolean(");
496 else if (sig[j] == Byte.TYPE) {
497 out.print("out.writeByte(");
499 else if (sig[j] == Character.TYPE) {
500 out.print("out.writeChar(");
502 else if (sig[j] == Short.TYPE) {
503 out.print("out.writeShort(");
505 else if (sig[j] == Integer.TYPE) {
506 out.print("out.writeInt(");
508 else if (sig[j] == Long.TYPE) {
509 out.print("out.writeLong(");
511 else if (sig[j] == Float.TYPE) {
512 out.print("out.writeFloat(");
514 else if (sig[j] == Double.TYPE) {
515 out.print("out.writeDouble(");
518 out.print("out.writeObject(");
520 out.print("$param_" + j + ");");
524 out.print("catch (java.io.IOException e) {");
526 out.print("throw new java.rmi.MarshalException(\"error marshalling arguments\", e);");
529 out.println("ref.invoke(call);");
530 if (returntype != Void.TYPE) {
531 out.println(getPrettyName(returntype) + " $result;");
535 out.print("java.io.ObjectInput in = call.getInputStream();");
536 boolean needcastcheck = false;
537 if (returntype != Void.TYPE) {
539 out.print("$result = ");
540 if (returntype == Boolean.TYPE) {
541 out.print("in.readBoolean();");
543 else if (returntype == Byte.TYPE) {
544 out.print("in.readByte();");
546 else if (returntype == Character.TYPE) {
547 out.print("in.readChar();");
549 else if (returntype == Short.TYPE) {
550 out.print("in.readShort();");
552 else if (returntype == Integer.TYPE) {
553 out.print("in.readInt();");
555 else if (returntype == Long.TYPE) {
556 out.print("in.readLong();");
558 else if (returntype == Float.TYPE) {
559 out.print("in.readFloat();");
561 else if (returntype == Double.TYPE) {
562 out.print("in.readDouble();");
565 if (returntype != Object.class) {
566 out.print("(" + getPrettyName(returntype) + ")");
569 needcastcheck = true;
571 out.print("in.readObject();");
574 out.print("return ($result);");
578 out.print("catch (java.io.IOException e) {");
580 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");
584 out.print("catch (java.lang.ClassNotFoundException e) {");
586 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);");
590 out.print("finally {");
592 out.print("ref.done(call);");
596 if (need12Stubs && need11Stubs) {
605 boolean needgeneral = true;
606 for (int j = 0; j < except.length; j++) {
608 out.print("catch (" + getPrettyName(except[j]) + " e) {");
610 out.print("throw e;");
613 if (except[j] == Exception.class) {
619 out.print("catch (java.lang.Exception e) {");
621 out.print("throw new java.rmi.UnexpectedException(\"undeclared checked exception\", e);");
637 private void generateSkel() throws IOException {
638 skelname = fullclassname + "_Skel";
639 String skelclassname = classname + "_Skel";
640 ctrl = new TabbedWriter(new FileWriter((destination == null ? "" : destination + File.separator)
641 + skelname.replace('.', File.separatorChar)
643 out = new PrintWriter(ctrl);
646 System.out.println("[Generating class " + skelname + ".java]");
649 out.println("// Skel class generated by rmic - DO NOT EDIT!");
651 if (fullclassname != classname) {
652 String pname = fullclassname.substring(0, fullclassname.lastIndexOf('.'));
653 out.println("package " + pname + ";");
657 out.print("public final class " + skelclassname);
660 // Output interfaces we implement
661 out.print("implements java.rmi.server.Skeleton");
667 // Interface hash - don't know how to calculate this - XXX
668 out.println("private static final long interfaceHash = " + RMIHashes.getInterfaceHash(clazz) + "L;");
672 out.print("private static final java.rmi.server.Operation[] operations = {");
675 for (int i = 0; i < remotemethods.length; i++) {
676 Method m = remotemethods[i].meth;
677 out.print("new java.rmi.server.Operation(\"");
678 out.print(getPrettyName(m.getReturnType()) + " ");
679 out.print(m.getName() + "(");
681 Class[] sig = m.getParameterTypes();
682 for (int j = 0; j < sig.length; j++) {
683 out.print(getPrettyName(sig[j]));
684 if (j+1 < sig.length) {
689 if (i + 1 < remotemethods.length) {
698 // getOperations method
699 out.print("public java.rmi.server.Operation[] getOperations() {");
701 out.print("return ((java.rmi.server.Operation[]) operations.clone());");
708 out.print("public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {");
711 out.print("if (opnum < 0) {");
714 for (int i = 0; i < remotemethods.length; i++) {
715 out.print("if (hash == " + Long.toString(remotemethods[i].hash) + "L) {");
717 out.print("opnum = " + i + ";");
724 out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");
730 out.print("else if (hash != interfaceHash) {");
732 out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");");
738 out.println(fullclassname + " server = (" + fullclassname + ")obj;");
739 out.println("switch (opnum) {");
742 for (int i = 0; i < remotemethods.length; i++) {
743 Method m = remotemethods[i].meth;
744 out.println("case " + i + ":");
748 Class[] sig = m.getParameterTypes();
749 for (int j = 0; j < sig.length; j++) {
750 out.print(getPrettyName(sig[j]));
751 out.println(" $param_" + j + ";");
755 boolean needcastcheck = false;
757 out.println("java.io.ObjectInput in = call.getInputStream();");
758 for (int j = 0; j < sig.length; j++) {
759 out.print("$param_" + j + " = ");
760 if (sig[j] == Boolean.TYPE) {
761 out.print("in.readBoolean();");
763 else if (sig[j] == Byte.TYPE) {
764 out.print("in.readByte();");
766 else if (sig[j] == Character.TYPE) {
767 out.print("in.readChar();");
769 else if (sig[j] == Short.TYPE) {
770 out.print("in.readShort();");
772 else if (sig[j] == Integer.TYPE) {
773 out.print("in.readInt();");
775 else if (sig[j] == Long.TYPE) {
776 out.print("in.readLong();");
778 else if (sig[j] == Float.TYPE) {
779 out.print("in.readFloat();");
781 else if (sig[j] == Double.TYPE) {
782 out.print("in.readDouble();");
785 if (sig[j] != Object.class) {
786 out.print("(" + getPrettyName(sig[j]) + ")");
787 needcastcheck = true;
789 out.print("in.readObject();");
795 out.print("catch (java.io.IOException e) {");
797 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");
801 out.print("catch (java.lang.ClassCastException e) {");
803 out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);");
807 out.print("finally {");
809 out.print("call.releaseInputStream();");
813 Class returntype = m.getReturnType();
814 if (returntype != Void.TYPE) {
815 out.print(getPrettyName(returntype) + " $result = ");
817 out.print("server." + m.getName() + "(");
818 for (int j = 0; j < sig.length; j++) {
819 out.print("$param_" + j);
820 if (j + 1 < sig.length) {
828 out.print("java.io.ObjectOutput out = call.getResultStream(true);");
829 if (returntype != Void.TYPE) {
831 if (returntype == Boolean.TYPE) {
832 out.print("out.writeBoolean($result);");
834 else if (returntype == Byte.TYPE) {
835 out.print("out.writeByte($result);");
837 else if (returntype == Character.TYPE) {
838 out.print("out.writeChar($result);");
840 else if (returntype == Short.TYPE) {
841 out.print("out.writeShort($result);");
843 else if (returntype == Integer.TYPE) {
844 out.print("out.writeInt($result);");
846 else if (returntype == Long.TYPE) {
847 out.print("out.writeLong($result);");
849 else if (returntype == Float.TYPE) {
850 out.print("out.writeFloat($result);");
852 else if (returntype == Double.TYPE) {
853 out.print("out.writeDouble($result);");
856 out.print("out.writeObject($result);");
861 out.print("catch (java.io.IOException e) {");
863 out.print("throw new java.rmi.MarshalException(\"error marshalling return\", e);");
873 out.print("default:");
875 out.print("throw new java.rmi.UnmarshalException(\"invalid method number\");");
888 private void compile(String name) throws Exception {
889 Compiler comp = Compiler.getInstance();
891 System.out.println("[Compiling class " + name + "]");
893 comp.setDestination(destination);
897 private static String getPrettyName(Class cls) {
898 StringBuffer str = new StringBuffer();
899 for (int count = 0;; count++) {
900 if (!cls.isArray()) {
901 str.append(cls.getName());
902 for (; count > 0; count--) {
905 return (str.toString());
907 cls = cls.getComponentType();
912 * Sort exceptions so the most general go last.
914 private Class[] sortExceptions(Class[] except) {
915 for (int i = 0; i < except.length; i++) {
916 for (int j = i+1; j < except.length; j++) {
917 if (except[i].isAssignableFrom(except[j])) {
918 Class tmp = except[i];
919 except[i] = except[j];
928 * Process the options until we find the first argument.
930 private void parseOptions() {
932 if (next >= args.length || args[next].charAt(0) != '-') {
935 String arg = args[next];
938 // Accept `--' options if they look long enough.
939 if (arg.length() > 3 && arg.charAt(0) == '-'
940 && arg.charAt(1) == '-')
941 arg = arg.substring(1);
943 if (arg.equals("-keep")) {
946 else if (arg.equals("-keepgenerated")) {
949 else if (arg.equals("-v1.1")) {
953 else if (arg.equals("-vcompat")) {
957 else if (arg.equals("-v1.2")) {
961 else if (arg.equals("-g")) {
963 else if (arg.equals("-depend")) {
965 else if (arg.equals("-nowarn")) {
967 else if (arg.equals("-verbose")) {
970 else if (arg.equals("-nocompile")) {
973 else if (arg.equals("-classpath")) {
976 else if (arg.equals("-help")) {
979 else if (arg.equals("-version")) {
980 System.out.println("rmic ("
981 + System.getProperty("java.vm.name")
983 + System.getProperty("java.vm.version"));
984 System.out.println();
985 System.out.println("Copyright 2002 Free Software Foundation, Inc.");
986 System.out.println("This is free software; see the source for copying conditions. There is NO");
987 System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
990 else if (arg.equals("-d")) {
991 destination = args[next];
994 else if (arg.charAt(1) == 'J') {
997 error("unrecognized option `" + arg + "'");
1003 * Looks for the java.rmi.Remote interface that that is implemented by theClazz.
1004 * @param theClazz the class to look in
1005 * @return the Remote interface of theClazz or null if theClazz does not implement a Remote interface
1007 private Class getRemoteInterface(Class theClazz)
1009 Class[] interfaces = theClazz.getInterfaces();
1010 for (int i = 0; i < interfaces.length; i++)
1012 if (java.rmi.Remote.class.isAssignableFrom(interfaces[i]))
1014 return interfaces[i];
1017 logError("Class "+ theClazz.getName()
1018 + " is not a remote object. It does not implement an interface that is a java.rmi.Remote-interface.");
1023 * Prints an error to System.err and increases the error count.
1026 private void logError(String theError){
1028 System.err.println("error:"+theError);
1031 private static void error(String message) {
1032 System.err.println("rmic: " + message);
1033 System.err.println("Try `rmic --help' for more information.");
1037 private static void usage() {
1039 "Usage: rmic [OPTION]... CLASS...\n" +
1041 " -keep Don't delete any intermediate files\n" +
1042 " -keepgenerated Same as -keep\n" +
1043 " -v1.1 Java 1.1 style stubs only\n" +
1044 " -vcompat Java 1.1 & Java 1.2 stubs\n" +
1045 " -v1.2 Java 1.2 style stubs only\n" +
1046 " -g * Generated debugging information\n" +
1047 " -depend * Recompile out-of-date files\n" +
1048 " -nowarn * Suppress warning messages\n" +
1049 " -nocompile Don't compile the generated files\n" +
1050 " -verbose Output what's going on\n" +
1051 " -classpath <path> * Use given path as classpath\n" +
1052 " -d <directory> Specify where to place generated classes\n" +
1053 " -J<flag> * Pass flag to Java\n" +
1054 " -help Print this help, then exit\n" +
1055 " -version Print version number, then exit\n" +
1057 " * Option currently ignored\n" +
1058 "Long options can be used with `--option' form as well."
1063 static class MethodRef
1064 implements Comparable {
1070 MethodRef(Method m) {
1072 // We match on the name - but what about overloading? - XXX
1074 hash = RMIHashes.getMethodHash(m);
1077 public int compareTo(Object obj) {
1078 MethodRef that = (MethodRef)obj;
1079 return (this.sig.compareTo(that.sig));