1 52 53 package com.go.trove.util; 54 55 import java.beans.*; 56 import java.io.*; 57 import java.util.*; 58 import java.lang.reflect.*; 59 import com.go.trove.classfile.*; 60 61 124 public class BeanComparator implements Comparator, Serializable { 125 private static Map cGeneratedComparatorCache; 127 128 static { 129 cGeneratedComparatorCache = new SoftHashMap(); 130 } 131 132 139 public static BeanComparator forClass(Class clazz) { 140 return new BeanComparator(clazz); 141 } 142 143 146 private static boolean equalTest(Object obj1, Object obj2) { 147 return (obj1 == obj2) ? true : 148 ((obj1 == null || obj2 == null) ? false : obj1.equals(obj2)); 149 } 150 151 154 161 162 private Class mBeanClass; 163 164 private transient Map mProperties; 166 167 private String mOrderByName; 168 169 private Comparator mUsingComparator; 170 171 private int mFlags; 175 176 private Comparator mCollator; 178 179 private BeanComparator mParent; 180 181 private transient Comparator mComparator; 183 184 private transient boolean mHasHashCode; 185 private transient int mHashCode; 186 187 private BeanComparator(Class clazz) { 188 mBeanClass = clazz; 189 mCollator = String.CASE_INSENSITIVE_ORDER; 190 } 191 192 private BeanComparator(BeanComparator parent) { 193 mParent = parent; 194 mBeanClass = parent.mBeanClass; 195 mProperties = parent.getProperties(); 196 mCollator = parent.mCollator; 197 } 198 199 226 public BeanComparator orderBy(String propertyName) 227 throws IllegalArgumentException 228 { 229 int dot = propertyName.indexOf('.'); 230 String subName; 231 if (dot < 0) { 232 subName = null; 233 } 234 else { 235 subName = propertyName.substring(dot + 1); 236 propertyName = propertyName.substring(0, dot); 237 } 238 239 PropertyDescriptor desc = 240 (PropertyDescriptor)getProperties().get(propertyName); 241 242 if (desc == null) { 243 throw new IllegalArgumentException 244 ("Property '" + propertyName + "' doesn't exist in '" + 245 mBeanClass.getName() + '\''); 246 } 247 248 if (desc.getPropertyType() == null) { 249 throw new IllegalArgumentException 250 ("Property '" + propertyName + "' is only an indexed type"); 251 } 252 253 if (desc.getReadMethod() == null) { 254 throw new IllegalArgumentException 255 ("Property '" + propertyName + "' cannot be read"); 256 } 257 258 if (propertyName.equals(mOrderByName)) { 259 propertyName = new String (propertyName); 264 } 265 266 BeanComparator bc = new BeanComparator(this); 267 bc.mOrderByName = propertyName; 268 269 if (subName != null) { 270 BeanComparator subOrder = forClass(desc.getPropertyType()); 271 subOrder.mCollator = mCollator; 272 bc = bc.using(subOrder.orderBy(subName)); 273 } 274 275 return bc; 276 } 277 278 293 public BeanComparator using(Comparator c) { 294 BeanComparator bc = new BeanComparator(this); 295 bc.mOrderByName = mOrderByName; 296 bc.mUsingComparator = c; 297 bc.mFlags = mFlags; 298 return bc; 299 } 300 301 306 public BeanComparator reverse() { 307 BeanComparator bc = new BeanComparator(this); 308 bc.mOrderByName = mOrderByName; 309 bc.mUsingComparator = mUsingComparator; 310 bc.mFlags = mFlags ^ 0x01; 311 return bc; 312 } 313 314 324 public BeanComparator nullHigh() { 325 BeanComparator bc = new BeanComparator(this); 326 bc.mOrderByName = mOrderByName; 327 bc.mUsingComparator = mUsingComparator; 328 bc.mFlags = mFlags ^ ((mFlags & 0x01) << 1); 329 return bc; 330 } 331 332 340 public BeanComparator nullLow() { 341 BeanComparator bc = new BeanComparator(this); 342 bc.mOrderByName = mOrderByName; 343 bc.mUsingComparator = mUsingComparator; 344 bc.mFlags = mFlags ^ ((~mFlags & 0x01) << 1); 345 return bc; 346 } 347 348 357 public BeanComparator caseSensitive() { 358 if ((mFlags & 0x04) != 0) { 359 return this; 361 } 362 BeanComparator bc = new BeanComparator(this); 363 bc.mOrderByName = mOrderByName; 364 bc.mUsingComparator = mUsingComparator; 365 bc.mFlags = mFlags | 0x04; 366 return bc; 367 } 368 369 383 public BeanComparator collate(Comparator c) { 384 BeanComparator bc = new BeanComparator(this); 385 bc.mOrderByName = mOrderByName; 386 bc.mUsingComparator = mUsingComparator; 387 bc.mFlags = mFlags & ~0x04; 388 bc.mCollator = c; 389 return bc; 390 } 391 392 public int compare(Object obj1, Object obj2) throws ClassCastException { 393 Comparator c = mComparator; 394 if (c == null) { 395 c = mComparator = generateComparator(); 396 } 397 return c.compare(obj1, obj2); 398 } 399 400 public int hashCode() { 401 if (!mHasHashCode) { 402 setHashCode(new Rules(this)); 403 } 404 return mHashCode; 405 } 406 407 private void setHashCode(Rules rules) { 408 mHashCode = rules.hashCode(); 409 mHasHashCode = true; 410 } 411 412 420 public boolean equals(Object obj) { 421 if (obj instanceof BeanComparator) { 422 BeanComparator bc = (BeanComparator)obj; 423 424 return mFlags == bc.mFlags && 425 equalTest(mBeanClass, bc.mBeanClass) && 426 equalTest(mOrderByName, bc.mOrderByName) && 427 equalTest(mUsingComparator, bc.mUsingComparator) && 428 equalTest(mCollator, bc.mCollator) && 429 equalTest(mParent, bc.mParent); 430 } 431 else { 432 return false; 433 } 434 } 435 436 private Map getProperties() { 437 if (mProperties == null) { 438 try { 439 mProperties = 440 CompleteIntrospector.getAllProperties(mBeanClass); 441 } 442 catch (IntrospectionException e) { 443 throw new RuntimeException (e.toString()); 444 } 445 } 446 return mProperties; 447 } 448 449 private Comparator generateComparator() { 450 Rules rules = new Rules(this); 451 452 if (!mHasHashCode) { 453 setHashCode(rules); 454 } 455 456 Class clazz; 457 458 synchronized (cGeneratedComparatorCache) { 459 Object c = cGeneratedComparatorCache.get(rules); 460 461 if (c == null) { 462 clazz = generateComparatorClass(rules); 463 cGeneratedComparatorCache.put(rules, clazz); 464 } 465 else if (c instanceof Comparator) { 466 return (Comparator)c; 467 } 468 else { 469 clazz = (Class )c; 470 } 471 472 BeanComparator[] ruleParts = rules.getRuleParts(); 473 Comparator[] collators = new Comparator[ruleParts.length]; 474 Comparator[] usingComparators = new Comparator[ruleParts.length]; 475 boolean singleton = true; 476 477 for (int i=0; i<ruleParts.length; i++) { 478 BeanComparator rp = ruleParts[i]; 479 Comparator c2 = rp.mCollator; 480 if ((collators[i] = c2) != null) { 481 if (c2 != String.CASE_INSENSITIVE_ORDER) { 482 singleton = false; 483 } 484 } 485 if ((usingComparators[i] = rp.mUsingComparator) != null) { 486 singleton = false; 487 } 488 } 489 490 try { 491 Constructor ctor = clazz.getDeclaredConstructor 492 (new Class [] {Comparator[].class, Comparator[].class}); 493 c = (Comparator)ctor.newInstance 494 (new Object [] {collators, usingComparators}); 495 } 496 catch (NoSuchMethodException e) { 497 throw new InternalError (e.toString()); 498 } 499 catch (InstantiationException e) { 500 throw new InternalError (e.toString()); 501 } 502 catch (IllegalAccessException e) { 503 throw new InternalError (e.toString()); 504 } 505 catch (IllegalArgumentException e) { 506 throw new InternalError (e.toString()); 507 } 508 catch (InvocationTargetException e) { 509 throw new InternalError (e.getTargetException().toString()); 510 } 511 512 if (singleton) { 513 cGeneratedComparatorCache.put(rules, c); 516 } 517 518 return (Comparator)c; 519 } 520 } 521 522 private Class generateComparatorClass(Rules rules) { 523 ClassInjector injector = 524 ClassInjector.getInstance(mBeanClass.getClassLoader()); 525 526 int id = rules.hashCode(); 527 528 String baseName = this.getClass().getName() + '$'; 529 String className = baseName; 530 try { 531 while (true) { 532 className = baseName + (id & 0xffffffffL); 533 try { 534 injector.loadClass(className); 535 } 536 catch (LinkageError e) { 537 } 538 id++; 539 } 540 } 541 catch (ClassNotFoundException e) { 542 } 543 544 ClassFile cf = generateClassFile(className, rules); 545 546 560 561 try { 562 OutputStream stream = injector.getStream(cf.getClassName()); 563 cf.writeTo(stream); 564 stream.close(); 565 } 566 catch (IOException e) { 567 throw new InternalError (e.toString()); 568 } 569 570 try { 571 return injector.loadClass(cf.getClassName()); 572 } 573 catch (ClassNotFoundException e) { 574 throw new InternalError (e.toString()); 575 } 576 } 577 578 private static ClassFile generateClassFile(String className, Rules rules) { 579 ClassFile cf = new ClassFile(className); 580 cf.markSynthetic(); 581 582 cf.addInterface(Comparator.class); 583 cf.addInterface(Serializable.class); 584 585 AccessFlags privateAccess = new AccessFlags(); 586 privateAccess.setPrivate(true); 587 AccessFlags publicAccess = new AccessFlags(); 588 publicAccess.setPublic(true); 589 590 TypeDescriptor comparatorType = new TypeDescriptor(Comparator.class); 592 TypeDescriptor comparatorArrayType = 593 new TypeDescriptor(comparatorType, 1); 594 cf.addField(privateAccess, 595 "mCollators", comparatorArrayType).markSynthetic(); 596 cf.addField(privateAccess, 597 "mUsingComparators", comparatorArrayType).markSynthetic(); 598 599 TypeDescriptor[] paramTypes = { 601 comparatorArrayType, comparatorArrayType 602 }; 603 MethodInfo ctor = cf.addConstructor(publicAccess, paramTypes); 604 ctor.markSynthetic(); 605 CodeBuilder builder = new CodeBuilder(ctor); 606 607 builder.loadThis(); 608 builder.invokeSuperConstructor(null); 609 builder.loadThis(); 610 builder.loadLocal(builder.getParameters()[0]); 611 builder.storeField("mCollators", comparatorArrayType); 612 builder.loadThis(); 613 builder.loadLocal(builder.getParameters()[1]); 614 builder.storeField("mUsingComparators", comparatorArrayType); 615 builder.returnVoid(); 616 617 Method compareMethod, compareToMethod; 619 try { 620 compareMethod = Comparator.class.getMethod 621 ("compare", new Class [] {Object .class, Object .class}); 622 compareToMethod = Comparable .class.getMethod 623 ("compareTo", new Class [] {Object .class}); 624 } 625 catch (NoSuchMethodException e) { 626 throw new InternalError (e.toString()); 627 } 628 629 MethodInfo mi = cf.addMethod(compareMethod); 630 mi.markSynthetic(); 631 builder = new CodeBuilder(mi); 632 633 Label endLabel = builder.createLabel(); 634 LocalVariable obj1 = builder.getParameters()[0]; 635 LocalVariable obj2 = builder.getParameters()[1]; 636 637 640 BeanComparator[] ruleParts = rules.getRuleParts(); 641 BeanComparator bc = ruleParts[0]; 642 643 if ((bc.mFlags & 0x01) != 0) { 644 LocalVariable temp = obj1; 646 obj1 = obj2; 647 obj2 = temp; 648 } 649 650 builder.loadLocal(obj1); 652 builder.loadLocal(obj2); 653 builder.ifEqualBranch(endLabel, true); 654 655 boolean nullHigh = (bc.mFlags & 0x02) == 0; 657 Label label = builder.createLabel(); 658 builder.loadLocal(obj1); 659 builder.ifNullBranch(label, false); 660 builder.loadConstant(nullHigh ? 1 : -1); 661 builder.returnValue(int.class); 662 label.setLocation(); 663 label = builder.createLabel(); 664 builder.loadLocal(obj2); 665 builder.ifNullBranch(label, false); 666 builder.loadConstant(nullHigh ? -1 : 1); 667 builder.returnValue(int.class); 668 label.setLocation(); 669 670 LocalVariable result = builder.createLocalVariable 672 ("result", new TypeDescriptor(int.class)); 673 if (bc.mUsingComparator != null) { 674 builder.loadThis(); 675 builder.loadField("mUsingComparators", comparatorArrayType); 676 builder.loadConstant(0); 677 builder.loadFromArray(Comparator.class); 678 builder.loadLocal(obj1); 679 builder.loadLocal(obj2); 680 builder.invoke(compareMethod); 681 builder.storeLocal(result); 682 builder.loadLocal(result); 683 label = builder.createLabel(); 684 builder.ifZeroComparisonBranch(label, "=="); 685 builder.loadLocal(result); 686 builder.returnValue(int.class); 687 label.setLocation(); 688 } 689 690 TypeDescriptor type = new TypeDescriptor(bc.mBeanClass); 693 builder.loadLocal(obj1); 694 builder.checkCast(type); 695 builder.storeLocal(obj1); 696 builder.loadLocal(obj2); 697 builder.checkCast(type); 698 builder.storeLocal(obj2); 699 700 for (int i=1; i<ruleParts.length; i++) { 702 bc = ruleParts[i]; 703 704 PropertyDescriptor desc = 705 (PropertyDescriptor)bc.getProperties().get(bc.mOrderByName); 706 Class propertyClass = desc.getPropertyType(); 707 TypeDescriptor propertyType = new TypeDescriptor(propertyClass); 708 709 LocalVariable p1 = builder.createLocalVariable("p1", propertyType); 711 LocalVariable p2 = builder.createLocalVariable("p2", propertyType); 712 713 builder.loadLocal(obj1); 715 builder.invoke(desc.getReadMethod()); 716 builder.storeLocal(p1); 717 builder.loadLocal(obj2); 718 builder.invoke(desc.getReadMethod()); 719 builder.storeLocal(p2); 720 721 if ((bc.mFlags & 0x01) != 0) { 722 LocalVariable temp = p1; 724 p1 = p2; 725 p2 = temp; 726 } 727 728 Label nextLabel = builder.createLabel(); 729 730 if (!propertyClass.isPrimitive()) { 732 builder.loadLocal(p1); 733 builder.loadLocal(p2); 734 builder.ifEqualBranch(nextLabel, true); 735 736 nullHigh = (bc.mFlags & 0x02) == 0; 738 label = builder.createLabel(); 739 builder.loadLocal(p1); 740 builder.ifNullBranch(label, false); 741 builder.loadConstant(nullHigh ? 1 : -1); 742 builder.returnValue(int.class); 743 label.setLocation(); 744 label = builder.createLabel(); 745 builder.loadLocal(p2); 746 builder.ifNullBranch(label, false); 747 builder.loadConstant(nullHigh ? -1 : 1); 748 builder.returnValue(int.class); 749 label.setLocation(); 750 } 751 752 if (bc.mUsingComparator != null) { 755 builder.loadThis(); 756 builder.loadField("mUsingComparators", comparatorArrayType); 757 builder.loadConstant(i); 758 builder.loadFromArray(Comparator.class); 759 loadAsObject(builder, propertyClass, p1); 760 loadAsObject(builder, propertyClass, p2); 761 builder.invoke(compareMethod); 762 } 763 else { 764 if ((bc.mFlags & 0x04) == 0 && bc.mCollator != null && 767 propertyClass.isAssignableFrom(String .class)) { 768 769 Label resultLabel = builder.createLabel(); 770 771 if (!String .class.isAssignableFrom(propertyClass)) { 772 776 TypeDescriptor stringType = 777 new TypeDescriptor(String .class); 778 779 builder.loadLocal(p1); 780 builder.instanceOf(stringType); 781 Label notString = builder.createLabel(); 782 builder.ifZeroComparisonBranch(notString, "=="); 783 builder.loadLocal(p2); 784 builder.instanceOf(stringType); 785 Label isString = builder.createLabel(); 786 builder.ifZeroComparisonBranch(isString, "!="); 787 788 notString.setLocation(); 789 generateComparableCompareTo 790 (builder, propertyClass, compareToMethod, 791 resultLabel, nextLabel, p1, p2); 792 793 isString.setLocation(); 794 } 795 796 builder.loadThis(); 797 builder.loadField("mCollators", comparatorArrayType); 798 builder.loadConstant(i); 799 builder.loadFromArray(Comparator.class); 800 builder.loadLocal(p1); 801 builder.loadLocal(p2); 802 builder.invoke(compareMethod); 803 804 resultLabel.setLocation(); 805 } 806 else if (propertyClass.isPrimitive()) { 807 generatePrimitiveComparison(builder, propertyClass, p1,p2); 808 } 809 else { 810 generateComparableCompareTo 812 (builder, propertyClass, compareToMethod, 813 null, nextLabel, p1, p2); 814 } 815 } 816 817 if (i < (ruleParts.length - 1)) { 818 builder.storeLocal(result); 819 builder.loadLocal(result); 820 builder.ifZeroComparisonBranch(nextLabel, "=="); 821 builder.loadLocal(result); 822 } 823 builder.returnValue(int.class); 824 825 nextLabel.setLocation(); 827 } 828 829 endLabel.setLocation(); 830 builder.loadConstant(0); 831 builder.returnValue(int.class); 832 833 return cf; 834 } 835 836 private static void loadAsObject(CodeBuilder builder, 837 Class type, LocalVariable v) 838 { 839 if (!type.isPrimitive()) { 840 builder.loadLocal(v); 841 return; 842 } 843 844 if (type == boolean.class) { 845 TypeDescriptor td = new TypeDescriptor(Boolean .class); 846 Label falseLabel = builder.createLabel(); 847 Label endLabel = builder.createLabel(); 848 builder.loadLocal(v); 849 builder.ifZeroComparisonBranch(falseLabel, "=="); 850 builder.loadStaticField("java.lang.Boolean", "TRUE", td); 851 builder.branch(endLabel); 852 falseLabel.setLocation(); 853 builder.loadStaticField("java.lang.Boolean", "FALSE", td); 854 endLabel.setLocation(); 855 return; 856 } 857 858 Class objectType; 859 860 if (type == int.class) { 861 objectType = Integer .class; 862 } 863 else if (type == long.class) { 864 objectType = Long .class; 865 } 866 else if (type == float.class) { 867 objectType = Float .class; 868 } 869 else if (type == double.class) { 870 objectType = Double .class; 871 } 872 else if (type == char.class) { 873 objectType = Character .class; 874 } 875 else if (type == byte.class) { 876 objectType = Byte .class; 877 } 878 else if (type == short.class) { 879 objectType = Short .class; 880 } 881 else { 882 objectType = type; 883 } 884 885 TypeDescriptor[] params = { 886 new TypeDescriptor(type) 887 }; 888 889 builder.newObject(new TypeDescriptor(objectType)); 890 builder.dup(); 891 builder.loadLocal(v); 892 builder.invokeConstructor(objectType.getName(), params); 893 } 894 895 private static void generatePrimitiveComparison(CodeBuilder builder, 896 Class type, 897 LocalVariable a, 898 LocalVariable b) 899 { 900 if (type == float.class) { 901 Label done = builder.createLabel(); 903 904 builder.loadLocal(a); 905 builder.loadLocal(b); 906 builder.math(Opcode.FCMPG); 907 Label label = builder.createLabel(); 908 builder.ifZeroComparisonBranch(label, ">="); 909 builder.loadConstant(-1); 910 builder.branch(done); 911 912 label.setLocation(); 913 builder.loadLocal(a); 914 builder.loadLocal(b); 915 builder.math(Opcode.FCMPL); 916 label = builder.createLabel(); 917 builder.ifZeroComparisonBranch(label, "<="); 918 builder.loadConstant(1); 919 builder.branch(done); 920 921 Method floatToIntBits; 922 try { 923 floatToIntBits = Float .class.getMethod 924 ("floatToIntBits", new Class [] {float.class}); 925 } 926 catch (NoSuchMethodException e) { 927 throw new InternalError (e.toString()); 928 } 929 930 label.setLocation(); 931 builder.loadLocal(a); 932 builder.invoke(floatToIntBits); 933 builder.convert(int.class, long.class); 934 builder.loadLocal(b); 935 builder.invoke(floatToIntBits); 936 builder.convert(int.class, long.class); 937 builder.math(Opcode.LCMP); 938 939 done.setLocation(); 940 } 941 else if (type == double.class) { 942 Label done = builder.createLabel(); 944 945 builder.loadLocal(a); 946 builder.loadLocal(b); 947 done = builder.createLabel(); 948 builder.math(Opcode.DCMPG); 949 Label label = builder.createLabel(); 950 builder.ifZeroComparisonBranch(label, ">="); 951 builder.loadConstant(-1); 952 builder.branch(done); 953 954 label.setLocation(); 955 builder.loadLocal(a); 956 builder.loadLocal(b); 957 builder.math(Opcode.DCMPL); 958 label = builder.createLabel(); 959 builder.ifZeroComparisonBranch(label, "<="); 960 builder.loadConstant(1); 961 builder.branch(done); 962 963 Method doubleToLongBits; 964 try { 965 doubleToLongBits = Double .class.getMethod 966 ("doubleToLongBits", new Class [] {double.class}); 967 } 968 catch (NoSuchMethodException e) { 969 throw new InternalError (e.toString()); 970 } 971 972 label.setLocation(); 973 builder.loadLocal(a); 974 builder.invoke(doubleToLongBits); 975 builder.loadLocal(b); 976 builder.invoke(doubleToLongBits); 977 builder.math(Opcode.LCMP); 978 979 done.setLocation(); 980 } 981 else if (type == long.class) { 982 builder.loadLocal(a); 983 builder.loadLocal(b); 984 builder.math(Opcode.LCMP); 985 } 986 else if (type == int.class) { 987 builder.loadLocal(a); 988 builder.convert(int.class, long.class); 989 builder.loadLocal(b); 990 builder.convert(int.class, long.class); 991 builder.math(Opcode.LCMP); 992 } 993 else { 994 builder.loadLocal(a); 995 builder.loadLocal(b); 996 builder.math(Opcode.ISUB); 997 } 998 } 999 1000 private static void generateComparableCompareTo(CodeBuilder builder, 1001 Class type, 1002 Method compareToMethod, 1003 Label goodLabel, 1004 Label nextLabel, 1005 LocalVariable a, 1006 LocalVariable b) 1007 { 1008 if (Comparable .class.isAssignableFrom(type)) { 1009 builder.loadLocal(a); 1010 builder.loadLocal(b); 1011 builder.invoke(compareToMethod); 1012 if (goodLabel != null) { 1013 builder.branch(goodLabel); 1014 } 1015 } 1016 else { 1017 TypeDescriptor comparableType = 1019 new TypeDescriptor(Comparable .class); 1020 1021 boolean locateGoodLabel = false; 1022 if (goodLabel == null) { 1023 goodLabel = builder.createLabel(); 1024 locateGoodLabel = true; 1025 } 1026 1027 Label tryStart = builder.createLabel().setLocation(); 1028 builder.loadLocal(a); 1029 builder.checkCast(comparableType); 1030 builder.loadLocal(b); 1031 builder.checkCast(comparableType); 1032 Label tryEnd = builder.createLabel().setLocation(); 1033 builder.invoke(compareToMethod); 1034 builder.branch(goodLabel); 1035 1036 builder.exceptionHandler(tryStart, tryEnd, 1037 ClassCastException .class.getName()); 1038 builder.pop(); 1041 if (nextLabel == null) { 1042 builder.loadConstant(0); 1043 } 1044 else { 1045 builder.branch(nextLabel); 1046 } 1047 1048 if (locateGoodLabel) { 1049 goodLabel.setLocation(); 1050 } 1051 } 1052 } 1053 1054 private static class Rules { 1056 private BeanComparator[] mRuleParts; 1057 private int mHashCode; 1058 1059 public Rules(BeanComparator bc) { 1060 mRuleParts = reduceRules(bc); 1061 1062 int hash = 0; 1064 1065 for (int i = mRuleParts.length - 1; i >= 0; i--) { 1066 bc = mRuleParts[i]; 1067 hash = 31 * hash; 1068 1069 hash += bc.mFlags << 4; 1070 1071 Object obj = bc.mBeanClass; 1072 if (obj != null) { 1073 hash += obj.hashCode(); 1074 } 1075 obj = bc.mOrderByName; 1076 if (obj != null) { 1077 hash += obj.hashCode(); 1078 } 1079 obj = bc.mUsingComparator; 1080 if (obj != null) { 1081 hash += obj.getClass().hashCode(); 1082 } 1083 obj = bc.mCollator; 1084 if (obj != null) { 1085 hash += obj.getClass().hashCode(); 1086 } 1087 } 1088 1089 mHashCode = hash; 1090 } 1091 1092 public BeanComparator[] getRuleParts() { 1093 return mRuleParts; 1094 } 1095 1096 public int hashCode() { 1097 return mHashCode; 1098 } 1099 1100 1104 public boolean equals(Object obj) { 1105 if (!(obj instanceof Rules)) { 1106 return false; 1107 } 1108 1109 BeanComparator[] ruleParts1 = getRuleParts(); 1110 BeanComparator[] ruleParts2 = ((Rules)obj).getRuleParts(); 1111 1112 if (ruleParts1.length != ruleParts2.length) { 1113 return false; 1114 } 1115 1116 for (int i=0; i<ruleParts1.length; i++) { 1117 BeanComparator bc1 = ruleParts1[i]; 1118 BeanComparator bc2 = ruleParts2[i]; 1119 1120 if (bc1.mFlags != bc2.mFlags) { 1121 return false; 1122 } 1123 if (!equalTest(bc1.mBeanClass, bc2.mBeanClass)) { 1124 return false; 1125 } 1126 if (!equalTest(bc1.mOrderByName, bc2.mOrderByName)) { 1127 return false; 1128 } 1129 if ((bc1.mUsingComparator == null) != 1130 (bc2.mUsingComparator == null)) { 1131 return false; 1132 } 1133 if ((bc1.mCollator == null) != (bc2.mCollator == null)) { 1134 return false; 1135 } 1136 } 1137 1138 return true; 1139 } 1140 1141 private BeanComparator[] reduceRules(BeanComparator bc) { 1142 List rules = new ArrayList(); 1145 1146 rules.add(bc); 1147 String name = bc.mOrderByName; 1148 1149 while ((bc = bc.mParent) != null) { 1150 if (name != bc.mOrderByName) { 1152 rules.add(bc); 1153 name = bc.mOrderByName; 1154 } 1155 } 1156 1157 int size = rules.size(); 1158 BeanComparator[] bcs = new BeanComparator[size]; 1159 for (int i=0; i<size; i++) { 1161 bcs[size - i - 1] = (BeanComparator)rules.get(i); 1162 } 1163 1164 return bcs; 1165 } 1166 } 1167} 1168 | Popular Tags |