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