001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.lang.builder; 018 019 import java.lang.reflect.AccessibleObject; 020 import java.lang.reflect.Field; 021 import java.lang.reflect.Modifier; 022 import java.util.Arrays; 023 import java.util.Collection; 024 import java.util.Collections; 025 import java.util.Comparator; 026 import java.util.List; 027 028 import org.apache.commons.lang.math.NumberUtils; 029 030 /** 031 * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. 032 * 033 * It is consistent with <code>equals(Object)</code> and 034 * <code>hashcode()</code> built with {@link EqualsBuilder} and 035 * {@link HashCodeBuilder}.</p> 036 * 037 * <p>Two Objects that compare equal using <code>equals(Object)</code> should normally 038 * also compare equal using <code>compareTo(Object)</code>.</p> 039 * 040 * <p>All relevant fields should be included in the calculation of the 041 * comparison. Derived fields may be ignored. The same fields, in the same 042 * order, should be used in both <code>compareTo(Object)</code> and 043 * <code>equals(Object)</code>.</p> 044 * 045 * <p>To use this class write code as follows:</p> 046 * 047 * <pre> 048 * public class MyClass { 049 * String field1; 050 * int field2; 051 * boolean field3; 052 * 053 * ... 054 * 055 * public int compareTo(Object o) { 056 * MyClass myClass = (MyClass) o; 057 * return new CompareToBuilder() 058 * .appendSuper(super.compareTo(o) 059 * .append(this.field1, myClass.field1) 060 * .append(this.field2, myClass.field2) 061 * .append(this.field3, myClass.field3) 062 * .toComparison(); 063 * } 064 * } 065 * </pre> 066 * 067 * <p>Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use 068 * reflection to determine the fields to append. Because fields can be private, 069 * <code>reflectionCompare</code> uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to 070 * bypass normal access control checks. This will fail under a security manager, 071 * unless the appropriate permissions are set up correctly. It is also 072 * slower than appending explicitly.</p> 073 * 074 * <p>A typical implementation of <code>compareTo(Object)</code> using 075 * <code>reflectionCompare</code> looks like:</p> 076 077 * <pre> 078 * public int compareTo(Object o) { 079 * return CompareToBuilder.reflectionCompare(this, o); 080 * } 081 * </pre> 082 * 083 * @see java.lang.Comparable 084 * @see java.lang.Object#equals(Object) 085 * @see java.lang.Object#hashCode() 086 * @see EqualsBuilder 087 * @see HashCodeBuilder 088 * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a> 089 * @author Stephen Colebourne 090 * @author Gary Gregory 091 * @author Pete Gieser 092 * @since 1.0 093 * @version $Id: CompareToBuilder.java 583666 2007-10-11 01:38:13Z ggregory $ 094 */ 095 public class CompareToBuilder { 096 097 /** 098 * Current state of the comparison as appended fields are checked. 099 */ 100 private int comparison; 101 102 /** 103 * <p>Constructor for CompareToBuilder.</p> 104 * 105 * <p>Starts off assuming that the objects are equal. Multiple calls are 106 * then made to the various append methods, followed by a call to 107 * {@link #toComparison} to get the result.</p> 108 */ 109 public CompareToBuilder() { 110 super(); 111 comparison = 0; 112 } 113 114 //----------------------------------------------------------------------- 115 /** 116 * <p>Compares two <code>Object</code>s via reflection.</p> 117 * 118 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 119 * is used to bypass normal access control checks. This will fail under a 120 * security manager unless the appropriate permissions are set.</p> 121 * 122 * <ul> 123 * <li>Static fields will not be compared</li> 124 * <li>Transient members will be not be compared, as they are likely derived 125 * fields</li> 126 * <li>Superclass fields will be compared</li> 127 * </ul> 128 * 129 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 130 * they are considered equal.</p> 131 * 132 * @param lhs left-hand object 133 * @param rhs right-hand object 134 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 135 * is less than, equal to, or greater than <code>rhs</code> 136 * @throws NullPointerException if either (but not both) parameters are 137 * <code>null</code> 138 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 139 * with <code>lhs</code> 140 */ 141 public static int reflectionCompare(Object lhs, Object rhs) { 142 return reflectionCompare(lhs, rhs, false, null, null); 143 } 144 145 /** 146 * <p>Compares two <code>Object</code>s via reflection.</p> 147 * 148 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 149 * is used to bypass normal access control checks. This will fail under a 150 * security manager unless the appropriate permissions are set.</p> 151 * 152 * <ul> 153 * <li>Static fields will not be compared</li> 154 * <li>If <code>compareTransients</code> is <code>true</code>, 155 * compares transient members. Otherwise ignores them, as they 156 * are likely derived fields.</li> 157 * <li>Superclass fields will be compared</li> 158 * </ul> 159 * 160 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 161 * they are considered equal.</p> 162 * 163 * @param lhs left-hand object 164 * @param rhs right-hand object 165 * @param compareTransients whether to compare transient fields 166 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 167 * is less than, equal to, or greater than <code>rhs</code> 168 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 169 * (but not both) is <code>null</code> 170 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 171 * with <code>lhs</code> 172 */ 173 public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) { 174 return reflectionCompare(lhs, rhs, compareTransients, null, null); 175 } 176 177 /** 178 * <p>Compares two <code>Object</code>s via reflection.</p> 179 * 180 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 181 * is used to bypass normal access control checks. This will fail under a 182 * security manager unless the appropriate permissions are set.</p> 183 * 184 * <ul> 185 * <li>Static fields will not be compared</li> 186 * <li>If <code>compareTransients</code> is <code>true</code>, 187 * compares transient members. Otherwise ignores them, as they 188 * are likely derived fields.</li> 189 * <li>Superclass fields will be compared</li> 190 * </ul> 191 * 192 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 193 * they are considered equal.</p> 194 * 195 * @param lhs left-hand object 196 * @param rhs right-hand object 197 * @param excludeFields Collection of String fields to exclude 198 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 199 * is less than, equal to, or greater than <code>rhs</code> 200 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 201 * (but not both) is <code>null</code> 202 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 203 * with <code>lhs</code> 204 * @since 2.2 205 */ 206 public static int reflectionCompare(Object lhs, Object rhs, Collection /*String*/ excludeFields) { 207 return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); 208 } 209 210 /** 211 * <p>Compares two <code>Object</code>s via reflection.</p> 212 * 213 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 214 * is used to bypass normal access control checks. This will fail under a 215 * security manager unless the appropriate permissions are set.</p> 216 * 217 * <ul> 218 * <li>Static fields will not be compared</li> 219 * <li>If <code>compareTransients</code> is <code>true</code>, 220 * compares transient members. Otherwise ignores them, as they 221 * are likely derived fields.</li> 222 * <li>Superclass fields will be compared</li> 223 * </ul> 224 * 225 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 226 * they are considered equal.</p> 227 * 228 * @param lhs left-hand object 229 * @param rhs right-hand object 230 * @param excludeFields array of fields to exclude 231 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 232 * is less than, equal to, or greater than <code>rhs</code> 233 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 234 * (but not both) is <code>null</code> 235 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 236 * with <code>lhs</code> 237 * @since 2.2 238 */ 239 public static int reflectionCompare(Object lhs, Object rhs, String[] excludeFields) { 240 return reflectionCompare(lhs, rhs, false, null, excludeFields); 241 } 242 243 /** 244 * <p>Compares two <code>Object</code>s via reflection.</p> 245 * 246 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 247 * is used to bypass normal access control checks. This will fail under a 248 * security manager unless the appropriate permissions are set.</p> 249 * 250 * <ul> 251 * <li>Static fields will not be compared</li> 252 * <li>If the <code>compareTransients</code> is <code>true</code>, 253 * compares transient members. Otherwise ignores them, as they 254 * are likely derived fields.</li> 255 * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>. 256 * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li> 257 * </ul> 258 * 259 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 260 * they are considered equal.</p> 261 * 262 * @param lhs left-hand object 263 * @param rhs right-hand object 264 * @param compareTransients whether to compare transient fields 265 * @param reflectUpToClass last superclass for which fields are compared 266 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 267 * is less than, equal to, or greater than <code>rhs</code> 268 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 269 * (but not both) is <code>null</code> 270 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 271 * with <code>lhs</code> 272 * @since 2.0 273 */ 274 public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients, 275 Class reflectUpToClass) 276 { 277 return reflectionCompare(lhs, rhs, false, reflectUpToClass, null); 278 } 279 280 /** 281 * <p>Compares two <code>Object</code>s via reflection.</p> 282 * 283 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 284 * is used to bypass normal access control checks. This will fail under a 285 * security manager unless the appropriate permissions are set.</p> 286 * 287 * <ul> 288 * <li>Static fields will not be compared</li> 289 * <li>If the <code>compareTransients</code> is <code>true</code>, 290 * compares transient members. Otherwise ignores them, as they 291 * are likely derived fields.</li> 292 * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>. 293 * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li> 294 * </ul> 295 * 296 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 297 * they are considered equal.</p> 298 * 299 * @param lhs left-hand object 300 * @param rhs right-hand object 301 * @param compareTransients whether to compare transient fields 302 * @param reflectUpToClass last superclass for which fields are compared 303 * @param excludeFields fields to exclude 304 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 305 * is less than, equal to, or greater than <code>rhs</code> 306 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 307 * (but not both) is <code>null</code> 308 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 309 * with <code>lhs</code> 310 * @since 2.2 311 */ 312 public static int reflectionCompare( 313 Object lhs, 314 Object rhs, 315 boolean compareTransients, 316 Class reflectUpToClass, 317 String[] excludeFields) { 318 319 if (lhs == rhs) { 320 return 0; 321 } 322 if (lhs == null || rhs == null) { 323 throw new NullPointerException(); 324 } 325 Class lhsClazz = lhs.getClass(); 326 if (!lhsClazz.isInstance(rhs)) { 327 throw new ClassCastException(); 328 } 329 CompareToBuilder compareToBuilder = new CompareToBuilder(); 330 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); 331 while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { 332 lhsClazz = lhsClazz.getSuperclass(); 333 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); 334 } 335 return compareToBuilder.toComparison(); 336 } 337 338 /** 339 * <p>Appends to <code>builder</code> the comparison of <code>lhs</code> 340 * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p> 341 * 342 * @param lhs left-hand object 343 * @param rhs right-hand object 344 * @param clazz <code>Class</code> that defines fields to be compared 345 * @param builder <code>CompareToBuilder</code> to append to 346 * @param useTransients whether to compare transient fields 347 * @param excludeFields fields to exclude 348 */ 349 private static void reflectionAppend( 350 Object lhs, 351 Object rhs, 352 Class clazz, 353 CompareToBuilder builder, 354 boolean useTransients, 355 String[] excludeFields) { 356 357 Field[] fields = clazz.getDeclaredFields(); 358 List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) : Collections.EMPTY_LIST; 359 AccessibleObject.setAccessible(fields, true); 360 for (int i = 0; i < fields.length && builder.comparison == 0; i++) { 361 Field f = fields[i]; 362 if (!excludedFieldList.contains(f.getName()) 363 && (f.getName().indexOf('$') == -1) 364 && (useTransients || !Modifier.isTransient(f.getModifiers())) 365 && (!Modifier.isStatic(f.getModifiers()))) { 366 try { 367 builder.append(f.get(lhs), f.get(rhs)); 368 } catch (IllegalAccessException e) { 369 // This can't happen. Would get a Security exception instead. 370 // Throw a runtime exception in case the impossible happens. 371 throw new InternalError("Unexpected IllegalAccessException"); 372 } 373 } 374 } 375 } 376 377 //----------------------------------------------------------------------- 378 /** 379 * <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code> 380 * result of the superclass.</p> 381 * 382 * @param superCompareTo result of calling <code>super.compareTo(Object)</code> 383 * @return this - used to chain append calls 384 * @since 2.0 385 */ 386 public CompareToBuilder appendSuper(int superCompareTo) { 387 if (comparison != 0) { 388 return this; 389 } 390 comparison = superCompareTo; 391 return this; 392 } 393 394 //----------------------------------------------------------------------- 395 /** 396 * <p>Appends to the <code>builder</code> the comparison of 397 * two <code>Object</code>s.</p> 398 * 399 * <ol> 400 * <li>Check if <code>lhs == rhs</code></li> 401 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>, 402 * a <code>null</code> object is less than a non-<code>null</code> object</li> 403 * <li>Check the object contents</li> 404 * </ol> 405 * 406 * <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p> 407 * 408 * @param lhs left-hand object 409 * @param rhs right-hand object 410 * @return this - used to chain append calls 411 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 412 * with <code>lhs</code> 413 */ 414 public CompareToBuilder append(Object lhs, Object rhs) { 415 return append(lhs, rhs, null); 416 } 417 418 /** 419 * <p>Appends to the <code>builder</code> the comparison of 420 * two <code>Object</code>s.</p> 421 * 422 * <ol> 423 * <li>Check if <code>lhs == rhs</code></li> 424 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>, 425 * a <code>null</code> object is less than a non-<code>null</code> object</li> 426 * <li>Check the object contents</li> 427 * </ol> 428 * 429 * <p>If <code>lhs</code> is an array, array comparison methods will be used. 430 * Otherwise <code>comparator</code> will be used to compare the objects. 431 * If <code>comparator</code> is <code>null</code>, <code>lhs</code> must 432 * implement {@link Comparable} instead.</p> 433 * 434 * @param lhs left-hand object 435 * @param rhs right-hand object 436 * @param comparator <code>Comparator</code> used to compare the objects, 437 * <code>null</code> means treat lhs as <code>Comparable</code> 438 * @return this - used to chain append calls 439 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 440 * with <code>lhs</code> 441 * @since 2.0 442 */ 443 public CompareToBuilder append(Object lhs, Object rhs, Comparator comparator) { 444 if (comparison != 0) { 445 return this; 446 } 447 if (lhs == rhs) { 448 return this; 449 } 450 if (lhs == null) { 451 comparison = -1; 452 return this; 453 } 454 if (rhs == null) { 455 comparison = +1; 456 return this; 457 } 458 if (lhs.getClass().isArray()) { 459 // switch on type of array, to dispatch to the correct handler 460 // handles multi dimensional arrays 461 // throws a ClassCastException if rhs is not the correct array type 462 if (lhs instanceof long[]) { 463 append((long[]) lhs, (long[]) rhs); 464 } else if (lhs instanceof int[]) { 465 append((int[]) lhs, (int[]) rhs); 466 } else if (lhs instanceof short[]) { 467 append((short[]) lhs, (short[]) rhs); 468 } else if (lhs instanceof char[]) { 469 append((char[]) lhs, (char[]) rhs); 470 } else if (lhs instanceof byte[]) { 471 append((byte[]) lhs, (byte[]) rhs); 472 } else if (lhs instanceof double[]) { 473 append((double[]) lhs, (double[]) rhs); 474 } else if (lhs instanceof float[]) { 475 append((float[]) lhs, (float[]) rhs); 476 } else if (lhs instanceof boolean[]) { 477 append((boolean[]) lhs, (boolean[]) rhs); 478 } else { 479 // not an array of primitives 480 // throws a ClassCastException if rhs is not an array 481 append((Object[]) lhs, (Object[]) rhs, comparator); 482 } 483 } else { 484 // the simple case, not an array, just test the element 485 if (comparator == null) { 486 comparison = ((Comparable) lhs).compareTo(rhs); 487 } else { 488 comparison = comparator.compare(lhs, rhs); 489 } 490 } 491 return this; 492 } 493 494 //------------------------------------------------------------------------- 495 /** 496 * Appends to the <code>builder</code> the comparison of 497 * two <code>long</code>s. 498 * 499 * @param lhs left-hand value 500 * @param rhs right-hand value 501 * @return this - used to chain append calls 502 */ 503 public CompareToBuilder append(long lhs, long rhs) { 504 if (comparison != 0) { 505 return this; 506 } 507 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0)); 508 return this; 509 } 510 511 /** 512 * Appends to the <code>builder</code> the comparison of 513 * two <code>int</code>s. 514 * 515 * @param lhs left-hand value 516 * @param rhs right-hand value 517 * @return this - used to chain append calls 518 */ 519 public CompareToBuilder append(int lhs, int rhs) { 520 if (comparison != 0) { 521 return this; 522 } 523 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0)); 524 return this; 525 } 526 527 /** 528 * Appends to the <code>builder</code> the comparison of 529 * two <code>short</code>s. 530 * 531 * @param lhs left-hand value 532 * @param rhs right-hand value 533 * @return this - used to chain append calls 534 */ 535 public CompareToBuilder append(short lhs, short rhs) { 536 if (comparison != 0) { 537 return this; 538 } 539 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0)); 540 return this; 541 } 542 543 /** 544 * Appends to the <code>builder</code> the comparison of 545 * two <code>char</code>s. 546 * 547 * @param lhs left-hand value 548 * @param rhs right-hand value 549 * @return this - used to chain append calls 550 */ 551 public CompareToBuilder append(char lhs, char rhs) { 552 if (comparison != 0) { 553 return this; 554 } 555 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0)); 556 return this; 557 } 558 559 /** 560 * Appends to the <code>builder</code> the comparison of 561 * two <code>byte</code>s. 562 * 563 * @param lhs left-hand value 564 * @param rhs right-hand value 565 * @return this - used to chain append calls 566 */ 567 public CompareToBuilder append(byte lhs, byte rhs) { 568 if (comparison != 0) { 569 return this; 570 } 571 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0)); 572 return this; 573 } 574 575 /** 576 * <p>Appends to the <code>builder</code> the comparison of 577 * two <code>double</code>s.</p> 578 * 579 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 580 * 581 * <p>It is compatible with the hash code generated by 582 * <code>HashCodeBuilder</code>.</p> 583 * 584 * @param lhs left-hand value 585 * @param rhs right-hand value 586 * @return this - used to chain append calls 587 */ 588 public CompareToBuilder append(double lhs, double rhs) { 589 if (comparison != 0) { 590 return this; 591 } 592 comparison = NumberUtils.compare(lhs, rhs); 593 return this; 594 } 595 596 /** 597 * <p>Appends to the <code>builder</code> the comparison of 598 * two <code>float</code>s.</p> 599 * 600 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 601 * 602 * <p>It is compatible with the hash code generated by 603 * <code>HashCodeBuilder</code>.</p> 604 * 605 * @param lhs left-hand value 606 * @param rhs right-hand value 607 * @return this - used to chain append calls 608 */ 609 public CompareToBuilder append(float lhs, float rhs) { 610 if (comparison != 0) { 611 return this; 612 } 613 comparison = NumberUtils.compare(lhs, rhs); 614 return this; 615 } 616 617 /** 618 * Appends to the <code>builder</code> the comparison of 619 * two <code>booleans</code>s. 620 * 621 * @param lhs left-hand value 622 * @param rhs right-hand value 623 * @return this - used to chain append calls 624 */ 625 public CompareToBuilder append(boolean lhs, boolean rhs) { 626 if (comparison != 0) { 627 return this; 628 } 629 if (lhs == rhs) { 630 return this; 631 } 632 if (lhs == false) { 633 comparison = -1; 634 } else { 635 comparison = +1; 636 } 637 return this; 638 } 639 640 //----------------------------------------------------------------------- 641 /** 642 * <p>Appends to the <code>builder</code> the deep comparison of 643 * two <code>Object</code> arrays.</p> 644 * 645 * <ol> 646 * <li>Check if arrays are the same using <code>==</code></li> 647 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 648 * <li>Check array length, a short length array is less than a long length array</li> 649 * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li> 650 * </ol> 651 * 652 * <p>This method will also will be called for the top level of multi-dimensional, 653 * ragged, and multi-typed arrays.</p> 654 * 655 * @param lhs left-hand array 656 * @param rhs right-hand array 657 * @return this - used to chain append calls 658 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 659 * with <code>lhs</code> 660 */ 661 public CompareToBuilder append(Object[] lhs, Object[] rhs) { 662 return append(lhs, rhs, null); 663 } 664 665 /** 666 * <p>Appends to the <code>builder</code> the deep comparison of 667 * two <code>Object</code> arrays.</p> 668 * 669 * <ol> 670 * <li>Check if arrays are the same using <code>==</code></li> 671 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 672 * <li>Check array length, a short length array is less than a long length array</li> 673 * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li> 674 * </ol> 675 * 676 * <p>This method will also will be called for the top level of multi-dimensional, 677 * ragged, and multi-typed arrays.</p> 678 * 679 * @param lhs left-hand array 680 * @param rhs right-hand array 681 * @param comparator <code>Comparator</code> to use to compare the array elements, 682 * <code>null</code> means to treat <code>lhs</code> elements as <code>Comparable</code>. 683 * @return this - used to chain append calls 684 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 685 * with <code>lhs</code> 686 * @since 2.0 687 */ 688 public CompareToBuilder append(Object[] lhs, Object[] rhs, Comparator comparator) { 689 if (comparison != 0) { 690 return this; 691 } 692 if (lhs == rhs) { 693 return this; 694 } 695 if (lhs == null) { 696 comparison = -1; 697 return this; 698 } 699 if (rhs == null) { 700 comparison = +1; 701 return this; 702 } 703 if (lhs.length != rhs.length) { 704 comparison = (lhs.length < rhs.length) ? -1 : +1; 705 return this; 706 } 707 for (int i = 0; i < lhs.length && comparison == 0; i++) { 708 append(lhs[i], rhs[i], comparator); 709 } 710 return this; 711 } 712 713 /** 714 * <p>Appends to the <code>builder</code> the deep comparison of 715 * two <code>long</code> arrays.</p> 716 * 717 * <ol> 718 * <li>Check if arrays are the same using <code>==</code></li> 719 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 720 * <li>Check array length, a shorter length array is less than a longer length array</li> 721 * <li>Check array contents element by element using {@link #append(long, long)}</li> 722 * </ol> 723 * 724 * @param lhs left-hand array 725 * @param rhs right-hand array 726 * @return this - used to chain append calls 727 */ 728 public CompareToBuilder append(long[] lhs, long[] rhs) { 729 if (comparison != 0) { 730 return this; 731 } 732 if (lhs == rhs) { 733 return this; 734 } 735 if (lhs == null) { 736 comparison = -1; 737 return this; 738 } 739 if (rhs == null) { 740 comparison = +1; 741 return this; 742 } 743 if (lhs.length != rhs.length) { 744 comparison = (lhs.length < rhs.length) ? -1 : +1; 745 return this; 746 } 747 for (int i = 0; i < lhs.length && comparison == 0; i++) { 748 append(lhs[i], rhs[i]); 749 } 750 return this; 751 } 752 753 /** 754 * <p>Appends to the <code>builder</code> the deep comparison of 755 * two <code>int</code> arrays.</p> 756 * 757 * <ol> 758 * <li>Check if arrays are the same using <code>==</code></li> 759 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 760 * <li>Check array length, a shorter length array is less than a longer length array</li> 761 * <li>Check array contents element by element using {@link #append(int, int)}</li> 762 * </ol> 763 * 764 * @param lhs left-hand array 765 * @param rhs right-hand array 766 * @return this - used to chain append calls 767 */ 768 public CompareToBuilder append(int[] lhs, int[] rhs) { 769 if (comparison != 0) { 770 return this; 771 } 772 if (lhs == rhs) { 773 return this; 774 } 775 if (lhs == null) { 776 comparison = -1; 777 return this; 778 } 779 if (rhs == null) { 780 comparison = +1; 781 return this; 782 } 783 if (lhs.length != rhs.length) { 784 comparison = (lhs.length < rhs.length) ? -1 : +1; 785 return this; 786 } 787 for (int i = 0; i < lhs.length && comparison == 0; i++) { 788 append(lhs[i], rhs[i]); 789 } 790 return this; 791 } 792 793 /** 794 * <p>Appends to the <code>builder</code> the deep comparison of 795 * two <code>short</code> arrays.</p> 796 * 797 * <ol> 798 * <li>Check if arrays are the same using <code>==</code></li> 799 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 800 * <li>Check array length, a shorter length array is less than a longer length array</li> 801 * <li>Check array contents element by element using {@link #append(short, short)}</li> 802 * </ol> 803 * 804 * @param lhs left-hand array 805 * @param rhs right-hand array 806 * @return this - used to chain append calls 807 */ 808 public CompareToBuilder append(short[] lhs, short[] rhs) { 809 if (comparison != 0) { 810 return this; 811 } 812 if (lhs == rhs) { 813 return this; 814 } 815 if (lhs == null) { 816 comparison = -1; 817 return this; 818 } 819 if (rhs == null) { 820 comparison = +1; 821 return this; 822 } 823 if (lhs.length != rhs.length) { 824 comparison = (lhs.length < rhs.length) ? -1 : +1; 825 return this; 826 } 827 for (int i = 0; i < lhs.length && comparison == 0; i++) { 828 append(lhs[i], rhs[i]); 829 } 830 return this; 831 } 832 833 /** 834 * <p>Appends to the <code>builder</code> the deep comparison of 835 * two <code>char</code> arrays.</p> 836 * 837 * <ol> 838 * <li>Check if arrays are the same using <code>==</code></li> 839 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 840 * <li>Check array length, a shorter length array is less than a longer length array</li> 841 * <li>Check array contents element by element using {@link #append(char, char)}</li> 842 * </ol> 843 * 844 * @param lhs left-hand array 845 * @param rhs right-hand array 846 * @return this - used to chain append calls 847 */ 848 public CompareToBuilder append(char[] lhs, char[] rhs) { 849 if (comparison != 0) { 850 return this; 851 } 852 if (lhs == rhs) { 853 return this; 854 } 855 if (lhs == null) { 856 comparison = -1; 857 return this; 858 } 859 if (rhs == null) { 860 comparison = +1; 861 return this; 862 } 863 if (lhs.length != rhs.length) { 864 comparison = (lhs.length < rhs.length) ? -1 : +1; 865 return this; 866 } 867 for (int i = 0; i < lhs.length && comparison == 0; i++) { 868 append(lhs[i], rhs[i]); 869 } 870 return this; 871 } 872 873 /** 874 * <p>Appends to the <code>builder</code> the deep comparison of 875 * two <code>byte</code> arrays.</p> 876 * 877 * <ol> 878 * <li>Check if arrays are the same using <code>==</code></li> 879 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 880 * <li>Check array length, a shorter length array is less than a longer length array</li> 881 * <li>Check array contents element by element using {@link #append(byte, byte)}</li> 882 * </ol> 883 * 884 * @param lhs left-hand array 885 * @param rhs right-hand array 886 * @return this - used to chain append calls 887 */ 888 public CompareToBuilder append(byte[] lhs, byte[] rhs) { 889 if (comparison != 0) { 890 return this; 891 } 892 if (lhs == rhs) { 893 return this; 894 } 895 if (lhs == null) { 896 comparison = -1; 897 return this; 898 } 899 if (rhs == null) { 900 comparison = +1; 901 return this; 902 } 903 if (lhs.length != rhs.length) { 904 comparison = (lhs.length < rhs.length) ? -1 : +1; 905 return this; 906 } 907 for (int i = 0; i < lhs.length && comparison == 0; i++) { 908 append(lhs[i], rhs[i]); 909 } 910 return this; 911 } 912 913 /** 914 * <p>Appends to the <code>builder</code> the deep comparison of 915 * two <code>double</code> arrays.</p> 916 * 917 * <ol> 918 * <li>Check if arrays are the same using <code>==</code></li> 919 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 920 * <li>Check array length, a shorter length array is less than a longer length array</li> 921 * <li>Check array contents element by element using {@link #append(double, double)}</li> 922 * </ol> 923 * 924 * @param lhs left-hand array 925 * @param rhs right-hand array 926 * @return this - used to chain append calls 927 */ 928 public CompareToBuilder append(double[] lhs, double[] rhs) { 929 if (comparison != 0) { 930 return this; 931 } 932 if (lhs == rhs) { 933 return this; 934 } 935 if (lhs == null) { 936 comparison = -1; 937 return this; 938 } 939 if (rhs == null) { 940 comparison = +1; 941 return this; 942 } 943 if (lhs.length != rhs.length) { 944 comparison = (lhs.length < rhs.length) ? -1 : +1; 945 return this; 946 } 947 for (int i = 0; i < lhs.length && comparison == 0; i++) { 948 append(lhs[i], rhs[i]); 949 } 950 return this; 951 } 952 953 /** 954 * <p>Appends to the <code>builder</code> the deep comparison of 955 * two <code>float</code> arrays.</p> 956 * 957 * <ol> 958 * <li>Check if arrays are the same using <code>==</code></li> 959 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 960 * <li>Check array length, a shorter length array is less than a longer length array</li> 961 * <li>Check array contents element by element using {@link #append(float, float)}</li> 962 * </ol> 963 * 964 * @param lhs left-hand array 965 * @param rhs right-hand array 966 * @return this - used to chain append calls 967 */ 968 public CompareToBuilder append(float[] lhs, float[] rhs) { 969 if (comparison != 0) { 970 return this; 971 } 972 if (lhs == rhs) { 973 return this; 974 } 975 if (lhs == null) { 976 comparison = -1; 977 return this; 978 } 979 if (rhs == null) { 980 comparison = +1; 981 return this; 982 } 983 if (lhs.length != rhs.length) { 984 comparison = (lhs.length < rhs.length) ? -1 : +1; 985 return this; 986 } 987 for (int i = 0; i < lhs.length && comparison == 0; i++) { 988 append(lhs[i], rhs[i]); 989 } 990 return this; 991 } 992 993 /** 994 * <p>Appends to the <code>builder</code> the deep comparison of 995 * two <code>boolean</code> arrays.</p> 996 * 997 * <ol> 998 * <li>Check if arrays are the same using <code>==</code></li> 999 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li> 1000 * <li>Check array length, a shorter length array is less than a longer length array</li> 1001 * <li>Check array contents element by element using {@link #append(boolean, boolean)}</li> 1002 * </ol> 1003 * 1004 * @param lhs left-hand array 1005 * @param rhs right-hand array 1006 * @return this - used to chain append calls 1007 */ 1008 public CompareToBuilder append(boolean[] lhs, boolean[] rhs) { 1009 if (comparison != 0) { 1010 return this; 1011 } 1012 if (lhs == rhs) { 1013 return this; 1014 } 1015 if (lhs == null) { 1016 comparison = -1; 1017 return this; 1018 } 1019 if (rhs == null) { 1020 comparison = +1; 1021 return this; 1022 } 1023 if (lhs.length != rhs.length) { 1024 comparison = (lhs.length < rhs.length) ? -1 : +1; 1025 return this; 1026 } 1027 for (int i = 0; i < lhs.length && comparison == 0; i++) { 1028 append(lhs[i], rhs[i]); 1029 } 1030 return this; 1031 } 1032 1033 //----------------------------------------------------------------------- 1034 /** 1035 * Returns a negative integer, a positive integer, or zero as 1036 * the <code>builder</code> has judged the "left-hand" side 1037 * as less than, greater than, or equal to the "right-hand" 1038 * side. 1039 * 1040 * @return final comparison result 1041 */ 1042 public int toComparison() { 1043 return comparison; 1044 } 1045 1046 } 1047