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