You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SubTypeComparator.java 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Common Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/cpl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.testing.compare.adapters;
  14. import org.aspectj.testing.compare.CompareUtil;
  15. import java.util.Comparator;
  16. // for testing code
  17. import java.util.*;
  18. import java.text.Collator;
  19. /**
  20. * This adopts pairs of [Class, Comparator]
  21. * and implements compare by delegation thereto,
  22. * selecting the first added where the classes of the both inputs
  23. * are assignable to the pair Class.
  24. * It first applies the null-semantics of CompareUtil.compare(..),
  25. * which holds that null values are less-than non-null values,
  26. * and that two nulls are equal.
  27. * Note that this class uses Object.equals(..)'s default reference
  28. * equality, so two SubTypeComparator with the same list
  29. * of delegates will NOT be considered equal.
  30. * <p>todo: This class is not thread-safe.
  31. * <p>todo: immutable: final list copy on construction to implement equals??
  32. */
  33. public class SubTypeComparator implements Comparator {
  34. /** order-sensitive comparators collection */
  35. private Vector comparators;
  36. /** copy of comparators for compare method */
  37. private Struct[] cache;
  38. /** default constructor */
  39. public SubTypeComparator () {
  40. comparators = new Vector();
  41. }
  42. /**
  43. * Return true if the Class is in the list of comparators
  44. * as of the initial execution of the method.
  45. * @param c the Class to look for a comparator
  46. * @return true of comparator exists for c
  47. */
  48. private boolean contains(Class c) {
  49. final int size = comparators.size();
  50. for (int i = 0; i < size; i++) {
  51. if (c == ((Struct) comparators.elementAt(i)).accepts) {
  52. return true;
  53. }
  54. }
  55. return false;
  56. }
  57. /**
  58. * Get copy of comparators for compare operation.
  59. */
  60. private Struct[] getComparators() { // todo: sync on comparators
  61. if ((null == cache) || (cache.length < comparators.size())) {
  62. cache = new Struct[comparators.size()];
  63. comparators.copyInto(cache);
  64. }
  65. return cache;
  66. }
  67. /**
  68. * Add a Class, Comparator pair as delegate when
  69. * both input are assignable to Class.
  70. * Note that additions are checked in the order they are added,
  71. * so add the lowest subtypes first. (i.e., if you add
  72. * a comparator for Class Object first, none of the others
  73. * will ever match.)
  74. * @param accepts the Class supertype of objects to accept
  75. * @param comparator the Comparator to use on such objects
  76. * @return false if not added, because either input is null
  77. * or because the Class is represented already.
  78. */
  79. public final boolean addComparator(Class accepts, Comparator comparator) {
  80. if ((null == accepts) || (null == comparator)
  81. || (contains(accepts))) {
  82. return false;
  83. }
  84. comparators.addElement(new Struct(accepts, comparator));
  85. return true;
  86. }
  87. /**
  88. * This implements compare by delegating
  89. * to the first input Comparator
  90. * where the class of the both input
  91. * is assignable to the pair Class.
  92. * It first enforces the null-semantics of CompareUtil.compare(..).
  93. * @throws ClassCastException if both input are not null and
  94. * they are not assignable to any registered Comparator.
  95. */
  96. public final int compare(Object lhs, Object rhs) {
  97. int result = CompareUtil.compare(lhs, rhs);
  98. if (Integer.MAX_VALUE == result) {
  99. Class lhClass = lhs.getClass() ;
  100. Class rhClass = rhs.getClass() ;
  101. Struct[] comp = getComparators();
  102. Class compClass;
  103. for (int i = 0; i < comp.length; i++) {
  104. compClass = comp[i].accepts;
  105. if ((compClass.isAssignableFrom(lhClass))
  106. && (compClass.isAssignableFrom(lhClass))) {
  107. return comp[i].comparator.compare(lhs, rhs);
  108. }
  109. }
  110. // not found - throw ClassCastException
  111. String mssg = "Unable to find Comparator for "
  112. + "lhs Class: " + lhClass.getName()
  113. + " rhs Class: " + rhClass.getName();
  114. throw new ClassCastException(mssg);
  115. }
  116. return result;
  117. }
  118. /**
  119. * (unnecessary) Struct to hold class-comparator pair
  120. * is preparation for using collections
  121. */
  122. static class Struct {
  123. public final Class accepts;
  124. public final Comparator comparator;
  125. /**
  126. * @param accepts the Class to accept input for - not null
  127. * @param comparator the Comparator to compare input with - not null
  128. */
  129. public Struct(Class accepts,Comparator comparator) {
  130. this.accepts = accepts;
  131. this.comparator = comparator;
  132. }
  133. /** delegate to accept hashcode */
  134. public int hashCode() { return accepts.hashCode() ; }
  135. /** WARNING: fast comparison based only on accept key reference identity */
  136. public boolean equals(Object o) {
  137. return ((null != o) && (o instanceof Struct)
  138. && (accepts == ((Struct)o).accepts));
  139. }
  140. } // class Struct
  141. //----------------------------------------------- test code
  142. /** test code */
  143. static class Test { // todo move elsewhere
  144. public void runTest(String[] args) {
  145. if ((null == args) || (1 > args.length)) {
  146. args = new String[] { "one", "two", "THREE", "FOUR", "fIVE", "6" };
  147. }
  148. SubTypeComparator me = new SubTypeComparator();
  149. String[] copy = new String[args.length];
  150. System.arraycopy(args, 0, copy, 0, copy.length);
  151. List list = Arrays.asList(args);
  152. Throwable result = test(me, list);
  153. if ((null == result)
  154. && (!ClassCastException.class.isAssignableFrom(result.getClass()))) {
  155. System.err.println("FAIL: expected cce: " + result);
  156. }
  157. me.addComparator(String.class, Collator.getInstance());
  158. me.addComparator(Object.class, new Comparator () {
  159. public int compare (Object lhs, Object rhs) {
  160. throw new Error("never used");
  161. }});
  162. result = test(me, list);
  163. if (null != result) {
  164. if (ClassCastException.class.isAssignableFrom(result.getClass())) {
  165. System.err.println("FAIL: unexpected cce: " + result);
  166. } else {
  167. System.err.println("FAIL: unexpected Throwable: " + result);
  168. }
  169. }
  170. // heterogeneous - pick Object
  171. Object[] temp = new Object[] { "string", new Integer(1) };
  172. result = test(me, Arrays.asList(temp));
  173. if ((null == result)
  174. && (!Error.class.isAssignableFrom(result.getClass()))) {
  175. System.err.println("FAIL: expected Error: " + result);
  176. }
  177. StringBuffer toPrint = print(Arrays.asList(copy), null);
  178. toPrint.append("\n");
  179. print(list, toPrint);
  180. System.err.println(toPrint.toString());
  181. }
  182. StringBuffer print(List list, StringBuffer sb) {
  183. if (null == sb) sb = new StringBuffer();
  184. sb.append("[");
  185. ListIterator iter = list.listIterator();
  186. while (iter.hasNext()) {
  187. sb.append(iter.next().toString());
  188. if (iter.hasNext()) sb.append(", ");
  189. }
  190. sb.append("]");
  191. return sb;
  192. }
  193. /**
  194. * run comparison, return true if got expected exception
  195. */
  196. Throwable test(Comparator c, List l) {
  197. try {
  198. Collections.sort(l,c);
  199. return null;
  200. } catch (Throwable r) {
  201. return r;
  202. }
  203. }
  204. } // class Test
  205. /** invoke Test.runTest(args) todo remove */
  206. public static void main(String[] args) {
  207. new Test().runTest(args);
  208. }
  209. } // class SubTypeComparator