/* Tools to implement run-time validation of a class against an interface, necessary if the interface is an ad hoc specification which was composed after the class was already developed and set in stone, so it'd be impossible to modify the class to formally "implement" the interface. Copyright 2005 by Robert Elton Maas, all rights reserved. Commercial or other for-profit use prohibited without prior written arrangements for payment of license fee or other consideration. Non-profit personal use allowed providing you notify me of your use within one week (7 days) of start of use. Non-profit organizational use allowed providing you ask me for permission prior to switching from personal testing-use to use as operational tool for organization. I (Robert Maas) developed this as a tool to aid my work on homework assignments for distributed-Java class at De Anza college, specifically to validate a sub-interface of HttpServletRequest etc. for a multi-UI test rig I plan to write next. */ import java.lang.reflect.Method; import java.util.Vector; import java.util.Enumeration; public class CompareIntCls { /* Given two methods, compare their signatures, returning -1,0,1 as appropriate. The specifics of comparison method aren't important, so long as this is a well-defined comparison on equivalence classes of methods. */ public static int compareMethodSignatures(Method m1, Method m2) { String name1 = m1.getName(); String name2 = m2.getName(); int sign = name1.compareTo(name2); if (sign!=0) return sign; Class[] parts1 = m1.getParameterTypes(); Class[] parts2 = m2.getParameterTypes(); for (int ixParm=0; ; ++ixParm) { if (ixParm >= parts1.length) { if (ixParm >= parts2.length) break; // All parameters matched, all exhausted now else return -1; } else { if (ixParm >= parts2.length) return 1; } sign = parts1[ixParm].toString().compareTo (parts2[ixParm].toString()); if (sign!=0) return sign; } return 0; // If nothing else different, assume they are equivalent } /* Given a Vector whose elements are all Methods, convert to an array of Methods. If caller has made a mistake, JVM signals runtime casting exception. */ public static Method[] vectorMethodsToArray(Vector meths) { Method[] res = new Method[meths.size()]; for (int ixres=0; ixres=doneSofar.size()) ? "(end)" : doneSofar.elementAt(ixhi))); */ if ((ixhi-ixlo)<2) { if (trace) System.out.println(" (those are adjacent, insert betw.)"); doneSofar.insertElementAt(oneOrig,ixhi); break; } int ixmi = (ixlo+ixhi)/2; Method oneMid = (Method)(doneSofar.elementAt(ixmi)); if (trace) System.out.println(" ixmi=" + ixmi + " " + doneSofar.elementAt(ixmi)); int sign = compareMethodSignatures(oneOrig, oneMid); //System.out.println(" (sign = " + sign + ")"); if (sign<0) { if (trace) System.out.println(" (First half)"); ixhi = ixmi; } else if (sign>0) { if (trace) System.out.println(" (Last half)"); ixlo = ixmi; } else { System.err.println("*** Duplicate signatures?\n* " + oneOrig + "\n* " + oneMid); throw new java.util.MissingResourceException ("Method signatures in array must be different","",""); } } if (trace) System.out.println(); } Method[] res = vectorMethodsToArray(doneSofar); return res; } /* Given a Vector, where each element is an array of two methods, show each pair of methods to allow visual comparison. But if the two print identically then show just one of them. */ public static void methodPairsShow(Vector pairs) { Enumeration en = pairs.elements(); while (en.hasMoreElements()) { Object obj = en.nextElement(); Method[] pair = (Method[])obj; Method m0 = pair[0]; Method m1 = pair[1]; String s0 = m0.toString(); String s1 = m1.toString(); if (s0.equals(s1)) System.out.println("= " + s0); else System.out.println("0 " + s0 + "\n1 " + s1); System.out.println(); } } /* For debugging, given an array o Methods, show them with info about each */ public static void methodsShow(Method[] ms) { methodsShow(ms, false); } public static void methodsShow(Method[] ms, boolean trace) { for (int i=0; i= msInt.length) { if (ixCls >= msCls.length) break; // All elements of both arrays exhausted else sign = 1; // Only interface exhausted, flush class } else { if (ixCls >= msCls.length) sign = -1; // Only class exhausted, flush interface else { // Nothing exhausted yet, so compare methods sign = compareMethodSignatures(msInt[ixInt], msCls[ixCls]); /* System.out.println("Comparison between:\n int: " + msInt[ixInt] + "\n cls: " + msCls[ixCls] + "\n result=" + sign); */ } } if (sign<0) onlyInt.add(msInt[ixInt++]); // Non-match int.method else if (sign>0) onlyCls.add(msCls[ixCls++]); // Non-mat cls.method else { // Match between int and cls, return both... Method[] pair = new Method[2]; pair[0] = msInt[ixInt++]; pair[1] = msCls[ixCls++]; inBoth.add(pair); } } Vector results = new Vector(); results.add(vectorMethodsToArray(onlyInt)); results.add(inBoth); results.add(vectorMethodsToArray(onlyCls)); return results; } /* Test rig for the tools defined in this file. */ public static void main(String args[]) { Class itf=null; Class cls=null; try { itf = Class.forName("MyInterface"); // Wanted 'int', but reserved cls = Class.forName("MyClass"); } catch (ClassNotFoundException ex) { System.out.println(ex); return; } System.out.println("** Interface: " + itf); Method[] ifms1 = itf.getMethods(); Method[] ifsor1 = sortMethodsBySignature(ifms1); methodsShow(ifsor1); System.out.println(); System.out.println("** Class: " + cls); Method[] ifms2 = cls.getMethods(); Method[] ifsor2 = sortMethodsBySignature(ifms2); methodsShow(ifsor2); System.out.println(); Vector trio = methodArraysCollate(ifsor1, ifsor2); System.out.println("** Only in interface:"); methodsShow((Method[])(trio.elementAt(0))); System.out.println(); /* System.out.println("** Only in class:"); methodsShow((Method[])(trio.elementAt(2))); System.out.println(); System.out.println("** In both interface and class:"); methodPairsShow((Vector)(trio.elementAt(1))); */ } } // End of class.