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