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.lang3.builder; 018 019 import java.lang.reflect.AccessibleObject; 020 import java.lang.reflect.Field; 021 import java.lang.reflect.Modifier; 022 import java.util.Collection; 023 import java.util.Comparator; 024 025 import org.apache.commons.lang3.ArrayUtils; 026 027 /** 028 * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. 029 * 030 * It is consistent with <code>equals(Object)</code> and 031 * <code>hashcode()</code> built with {@link EqualsBuilder} and 032 * {@link HashCodeBuilder}.</p> 033 * 034 * <p>Two Objects that compare equal using <code>equals(Object)</code> should normally 035 * also compare equal using <code>compareTo(Object)</code>.</p> 036 * 037 * <p>All relevant fields should be included in the calculation of the 038 * comparison. Derived fields may be ignored. The same fields, in the same 039 * order, should be used in both <code>compareTo(Object)</code> and 040 * <code>equals(Object)</code>.</p> 041 * 042 * <p>To use this class write code as follows:</p> 043 * 044 * <pre> 045 * public class MyClass { 046 * String field1; 047 * int field2; 048 * boolean field3; 049 * 050 * ... 051 * 052 * public int compareTo(Object o) { 053 * MyClass myClass = (MyClass) o; 054 * return new CompareToBuilder() 055 * .appendSuper(super.compareTo(o) 056 * .append(this.field1, myClass.field1) 057 * .append(this.field2, myClass.field2) 058 * .append(this.field3, myClass.field3) 059 * .toComparison(); 060 * } 061 * } 062 * </pre> 063 * 064 * <p>Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use 065 * reflection to determine the fields to append. Because fields can be private, 066 * <code>reflectionCompare</code> uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to 067 * bypass normal access control checks. This will fail under a security manager, 068 * unless the appropriate permissions are set up correctly. It is also 069 * slower than appending explicitly.</p> 070 * 071 * <p>A typical implementation of <code>compareTo(Object)</code> using 072 * <code>reflectionCompare</code> looks like:</p> 073 074 * <pre> 075 * public int compareTo(Object o) { 076 * return CompareToBuilder.reflectionCompare(this, o); 077 * } 078 * </pre> 079 * 080 * @see java.lang.Comparable 081 * @see java.lang.Object#equals(Object) 082 * @see java.lang.Object#hashCode() 083 * @see EqualsBuilder 084 * @see HashCodeBuilder 085 * @author Apache Software Foundation 086 * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a> 087 * @author Gary Gregory 088 * @author Pete Gieser 089 * @since 1.0 090 * @version $Id: CompareToBuilder.java 965941 2010-07-20 18:10:34Z bayard $ 091 */ 092 public class CompareToBuilder implements Builder<Integer> { 093 094 /** 095 * Current state of the comparison as appended fields are checked. 096 */ 097 private int comparison; 098 099 /** 100 * <p>Constructor for CompareToBuilder.</p> 101 * 102 * <p>Starts off assuming that the objects are equal. Multiple calls are 103 * then made to the various append methods, followed by a call to 104 * {@link #toComparison} to get the result.</p> 105 */ 106 public CompareToBuilder() { 107 super(); 108 comparison = 0; 109 } 110 111 //----------------------------------------------------------------------- 112 /** 113 * <p>Compares two <code>Object</code>s via reflection.</p> 114 * 115 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 116 * is used to bypass normal access control checks. This will fail under a 117 * security manager unless the appropriate permissions are set.</p> 118 * 119 * <ul> 120 * <li>Static fields will not be compared</li> 121 * <li>Transient members will be not be compared, as they are likely derived 122 * fields</li> 123 * <li>Superclass fields will be compared</li> 124 * </ul> 125 * 126 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 127 * they are considered equal.</p> 128 * 129 * @param lhs left-hand object 130 * @param rhs right-hand object 131 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 132 * is less than, equal to, or greater than <code>rhs</code> 133 * @throws NullPointerException if either (but not both) parameters are 134 * <code>null</code> 135 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 136 * with <code>lhs</code> 137 */ 138 public static int reflectionCompare(Object lhs, Object rhs) { 139 return reflectionCompare(lhs, rhs, false, null, null); 140 } 141 142 /** 143 * <p>Compares two <code>Object</code>s via reflection.</p> 144 * 145 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 146 * is used to bypass normal access control checks. This will fail under a 147 * security manager unless the appropriate permissions are set.</p> 148 * 149 * <ul> 150 * <li>Static fields will not be compared</li> 151 * <li>If <code>compareTransients</code> is <code>true</code>, 152 * compares transient members. Otherwise ignores them, as they 153 * are likely derived fields.</li> 154 * <li>Superclass fields will be compared</li> 155 * </ul> 156 * 157 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 158 * they are considered equal.</p> 159 * 160 * @param lhs left-hand object 161 * @param rhs right-hand object 162 * @param compareTransients whether to compare transient fields 163 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 164 * is less than, equal to, or greater than <code>rhs</code> 165 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 166 * (but not both) is <code>null</code> 167 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 168 * with <code>lhs</code> 169 */ 170 public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) { 171 return reflectionCompare(lhs, rhs, compareTransients, null, null); 172 } 173 174 /** 175 * <p>Compares two <code>Object</code>s via reflection.</p> 176 * 177 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 178 * is used to bypass normal access control checks. This will fail under a 179 * security manager unless the appropriate permissions are set.</p> 180 * 181 * <ul> 182 * <li>Static fields will not be compared</li> 183 * <li>If <code>compareTransients</code> is <code>true</code>, 184 * compares transient members. Otherwise ignores them, as they 185 * are likely derived fields.</li> 186 * <li>Superclass fields will be compared</li> 187 * </ul> 188 * 189 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 190 * they are considered equal.</p> 191 * 192 * @param lhs left-hand object 193 * @param rhs right-hand object 194 * @param excludeFields Collection of String fields to exclude 195 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 196 * is less than, equal to, or greater than <code>rhs</code> 197 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 198 * (but not both) is <code>null</code> 199 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 200 * with <code>lhs</code> 201 * @since 2.2 202 */ 203 public static int reflectionCompare(Object lhs, Object rhs, Collection<String> excludeFields) { 204 return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); 205 } 206 207 /** 208 * <p>Compares two <code>Object</code>s via reflection.</p> 209 * 210 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 211 * is used to bypass normal access control checks. This will fail under a 212 * security manager unless the appropriate permissions are set.</p> 213 * 214 * <ul> 215 * <li>Static fields will not be compared</li> 216 * <li>If <code>compareTransients</code> is <code>true</code>, 217 * compares transient members. Otherwise ignores them, as they 218 * are likely derived fields.</li> 219 * <li>Superclass fields will be compared</li> 220 * </ul> 221 * 222 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 223 * they are considered equal.</p> 224 * 225 * @param lhs left-hand object 226 * @param rhs right-hand object 227 * @param excludeFields array of fields to exclude 228 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 229 * is less than, equal to, or greater than <code>rhs</code> 230 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 231 * (but not both) is <code>null</code> 232 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 233 * with <code>lhs</code> 234 * @since 2.2 235 */ 236 public static int reflectionCompare(Object lhs, Object rhs, String[] excludeFields) { 237 return reflectionCompare(lhs, rhs, false, null, excludeFields); 238 } 239 240 /** 241 * <p>Compares two <code>Object</code>s via reflection.</p> 242 * 243 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 244 * is used to bypass normal access control checks. This will fail under a 245 * security manager unless the appropriate permissions are set.</p> 246 * 247 * <ul> 248 * <li>Static fields will not be compared</li> 249 * <li>If the <code>compareTransients</code> is <code>true</code>, 250 * compares transient members. Otherwise ignores them, as they 251 * are likely derived fields.</li> 252 * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>. 253 * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li> 254 * </ul> 255 * 256 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 257 * they are considered equal.</p> 258 * 259 * @param lhs left-hand object 260 * @param rhs right-hand object 261 * @param compareTransients whether to compare transient fields 262 * @param reflectUpToClass last superclass for which fields are compared 263 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 264 * is less than, equal to, or greater than <code>rhs</code> 265 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 266 * (but not both) is <code>null</code> 267 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 268 * with <code>lhs</code> 269 * @since 2.0 270 */ 271 public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients, 272 Class<?> reflectUpToClass) 273 { 274 return reflectionCompare(lhs, rhs, compareTransients, reflectUpToClass, null); 275 } 276 277 /** 278 * <p>Compares two <code>Object</code>s via reflection.</p> 279 * 280 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code> 281 * is used to bypass normal access control checks. This will fail under a 282 * security manager unless the appropriate permissions are set.</p> 283 * 284 * <ul> 285 * <li>Static fields will not be compared</li> 286 * <li>If the <code>compareTransients</code> is <code>true</code>, 287 * compares transient members. Otherwise ignores them, as they 288 * are likely derived fields.</li> 289 * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>. 290 * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li> 291 * </ul> 292 * 293 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>, 294 * they are considered equal.</p> 295 * 296 * @param lhs left-hand object 297 * @param rhs right-hand object 298 * @param compareTransients whether to compare transient fields 299 * @param reflectUpToClass last superclass for which fields are compared 300 * @param excludeFields fields to exclude 301 * @return a negative integer, zero, or a positive integer as <code>lhs</code> 302 * is less than, equal to, or greater than <code>rhs</code> 303 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code> 304 * (but not both) is <code>null</code> 305 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 306 * with <code>lhs</code> 307 * @since 2.2 308 */ 309 public static int reflectionCompare( 310 Object lhs, 311 Object rhs, 312 boolean compareTransients, 313 Class<?> reflectUpToClass, 314 String[] excludeFields) { 315 316 if (lhs == rhs) { 317 return 0; 318 } 319 if (lhs == null || rhs == null) { 320 throw new NullPointerException(); 321 } 322 Class<?> lhsClazz = lhs.getClass(); 323 if (!lhsClazz.isInstance(rhs)) { 324 throw new ClassCastException(); 325 } 326 CompareToBuilder compareToBuilder = new CompareToBuilder(); 327 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); 328 while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { 329 lhsClazz = lhsClazz.getSuperclass(); 330 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); 331 } 332 return compareToBuilder.toComparison(); 333 } 334 335 /** 336 * <p>Appends to <code>builder</code> the comparison of <code>lhs</code> 337 * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p> 338 * 339 * @param lhs left-hand object 340 * @param rhs right-hand object 341 * @param clazz <code>Class</code> that defines fields to be compared 342 * @param builder <code>CompareToBuilder</code> to append to 343 * @param useTransients whether to compare transient fields 344 * @param excludeFields fields to exclude 345 */ 346 private static void reflectionAppend( 347 Object lhs, 348 Object rhs, 349 Class<?> clazz, 350 CompareToBuilder builder, 351 boolean useTransients, 352 String[] excludeFields) { 353 354 Field[] fields = clazz.getDeclaredFields(); 355 AccessibleObject.setAccessible(fields, true); 356 for (int i = 0; i < fields.length && builder.comparison == 0; i++) { 357 Field f = fields[i]; 358 if (!ArrayUtils.contains(excludeFields, f.getName()) 359 && (f.getName().indexOf('$') == -1) 360 && (useTransients || !Modifier.isTransient(f.getModifiers())) 361 && (!Modifier.isStatic(f.getModifiers()))) { 362 try { 363 builder.append(f.get(lhs), f.get(rhs)); 364 } catch (IllegalAccessException e) { 365 // This can't happen. Would get a Security exception instead. 366 // Throw a runtime exception in case the impossible happens. 367 throw new InternalError("Unexpected IllegalAccessException"); 368 } 369 } 370 } 371 } 372 373 //----------------------------------------------------------------------- 374 /** 375 * <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code> 376 * result of the superclass.</p> 377 * 378 * @param superCompareTo result of calling <code>super.compareTo(Object)</code> 379 * @return this - used to chain append calls 380 * @since 2.0 381 */ 382 public CompareToBuilder appendSuper(int superCompareTo) { 383 if (comparison != 0) { 384 return this; 385 } 386 comparison = superCompareTo; 387 return this; 388 } 389 390 //----------------------------------------------------------------------- 391 /** 392 * <p>Appends to the <code>builder</code> the comparison of 393 * two <code>Object</code>s.</p> 394 * 395 * <ol> 396 * <li>Check if <code>lhs == rhs</code></li> 397 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>, 398 * a <code>null</code> object is less than a non-<code>null</code> object</li> 399 * <li>Check the object contents</li> 400 * </ol> 401 * 402 * <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p> 403 * 404 * @param lhs left-hand object 405 * @param rhs right-hand object 406 * @return this - used to chain append calls 407 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 408 * with <code>lhs</code> 409 */ 410 public CompareToBuilder append(Object lhs, Object rhs) { 411 return append(lhs, rhs, null); 412 } 413 414 /** 415 * <p>Appends to the <code>builder</code> the comparison of 416 * two <code>Object</code>s.</p> 417 * 418 * <ol> 419 * <li>Check if <code>lhs == rhs</code></li> 420 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>, 421 * a <code>null</code> object is less than a non-<code>null</code> object</li> 422 * <li>Check the object contents</li> 423 * </ol> 424 * 425 * <p>If <code>lhs</code> is an array, array comparison methods will be used. 426 * Otherwise <code>comparator</code> will be used to compare the objects. 427 * If <code>comparator</code> is <code>null</code>, <code>lhs</code> must 428 * implement {@link Comparable} instead.</p> 429 * 430 * @param lhs left-hand object 431 * @param rhs right-hand object 432 * @param comparator <code>Comparator</code> used to compare the objects, 433 * <code>null</code> means treat lhs as <code>Comparable</code> 434 * @return this - used to chain append calls 435 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible 436 * with <code>lhs</code> 437 * @since 2.0 438 */ 439 public CompareToBuilder append(Object lhs, Object rhs, Comparator<?> comparator) { 440 if (comparison != 0) { 441 return this; 442 } 443 if (lhs == rhs) { 444 return this; 445 } 446 if (lhs == null) { 447 comparison = -1; 448 return this; 449 } 450 if (rhs == null) { 451 comparison = +1; 452 return this; 453 } 454 if (lhs.getClass().isArray()) { 455 // switch on type of array, to dispatch to the correct handler 456 // handles multi dimensional arrays 457 // throws a ClassCastException if rhs is not the correct array type 458 if (lhs instanceof long[]) { 459 append((long[]) lhs, (long[]) rhs); 460 } else if (lhs instanceof int[]) { 461 append((int[]) lhs, (int[]) rhs); 462 } else if (lhs instanceof short[]) { 463 append((short[]) lhs, (short[]) rhs); 464 } else if (lhs instanceof char[]) { 465 append((char[]) lhs, (char[]) rhs); 466 } else if (lhs instanceof byte[]) { 467 append((byte[]) lhs, (byte[]) rhs); 468 } else if (lhs instanceof double[]) { 469 append((double[]) lhs, (double[]) rhs); 470 } else if (lhs instanceof float[]) { 471 append((float[]) lhs, (float[]) rhs); 472 } else if (lhs instanceof boolean[]) { 473 append((boolean[]) lhs, (boolean[]) rhs); 474 } else { 475 // not an array of primitives 476 // throws a ClassCastException if rhs is not an array 477 append((Object[]) lhs, (Object[]) rhs, comparator); 478 } 479 } else { 480 // the simple case, not an array, just test the element 481 if (comparator == null) { 482 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc 483 final Comparable<Object> comparable = (Comparable<Object>) lhs; 484 comparison = comparable.compareTo(rhs); 485 } else { 486 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc 487 final Comparator<Object> comparator2 = (Comparator<Object>) comparator; 488 comparison = comparator2.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 = Double.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 = Float.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 * Returns a negative integer, a positive integer, or zero as 1048 * the <code>builder</code> has judged the "left-hand" side 1049 * as less than, greater than, or equal to the "right-hand" 1050 * side. 1051 * 1052 * @return final comparison result 1053 * 1054 * @since 3.0 1055 */ 1056 public Integer build() { 1057 return toComparison(); 1058 } 1059 } 1060