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.HashSet; 024 import java.util.Set; 025 026 import org.apache.commons.lang3.ArrayUtils; 027 import org.apache.commons.lang3.tuple.Pair; 028 029 /** 030 * <p>Assists in implementing {@link Object#equals(Object)} methods.</p> 031 * 032 * <p> This class provides methods to build a good equals method for any 033 * class. It follows rules laid out in 034 * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a> 035 * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>, 036 * <code>floats</code>, and arrays can be tricky. Also, making sure that 037 * <code>equals()</code> and <code>hashCode()</code> are consistent can be 038 * difficult.</p> 039 * 040 * <p>Two Objects that compare as equals must generate the same hash code, 041 * but two Objects with the same hash code do not have to be equal.</p> 042 * 043 * <p>All relevant fields should be included in the calculation of equals. 044 * Derived fields may be ignored. In particular, any field used in 045 * generating a hash code must be used in the equals method, and vice 046 * versa.</p> 047 * 048 * <p>Typical use for the code is as follows:</p> 049 * <pre> 050 * public boolean equals(Object obj) { 051 * if (obj == null) { return false; } 052 * if (obj == this) { return true; } 053 * if (obj.getClass() != getClass()) { 054 * return false; 055 * } 056 * MyClass rhs = (MyClass) obj; 057 * return new EqualsBuilder() 058 * .appendSuper(super.equals(obj)) 059 * .append(field1, rhs.field1) 060 * .append(field2, rhs.field2) 061 * .append(field3, rhs.field3) 062 * .isEquals(); 063 * } 064 * </pre> 065 * 066 * <p> Alternatively, there is a method that uses reflection to determine 067 * the fields to test. Because these fields are usually private, the method, 068 * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to 069 * change the visibility of the fields. This will fail under a security 070 * manager, unless the appropriate permissions are set up correctly. It is 071 * also slower than testing explicitly.</p> 072 * 073 * <p> A typical invocation for this method would look like:</p> 074 * <pre> 075 * public boolean equals(Object obj) { 076 * return EqualsBuilder.reflectionEquals(this, obj); 077 * } 078 * </pre> 079 * 080 * @since 1.0 081 * @version $Id: EqualsBuilder.java 1091531 2011-04-12 18:29:49Z ggregory $ 082 */ 083 public class EqualsBuilder implements Builder<Boolean> { 084 085 /** 086 * <p> 087 * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops. 088 * </p> 089 * 090 * @since 3.0 091 */ 092 private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<Set<Pair<IDKey, IDKey>>>(); 093 094 /* 095 * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode() 096 * we are in the process of calculating. 097 * 098 * So we generate a one-to-one mapping from the original object to a new object. 099 * 100 * Now HashSet uses equals() to determine if two elements with the same hashcode really 101 * are equal, so we also need to ensure that the replacement objects are only equal 102 * if the original objects are identical. 103 * 104 * The original implementation (2.4 and before) used the System.indentityHashCode() 105 * method - however this is not guaranteed to generate unique ids (e.g. LANG-459) 106 * 107 * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey) 108 * to disambiguate the duplicate ids. 109 */ 110 111 /** 112 * <p> 113 * Returns the registry of object pairs being traversed by the reflection 114 * methods in the current thread. 115 * </p> 116 * 117 * @return Set the registry of objects being traversed 118 * @since 3.0 119 */ 120 static Set<Pair<IDKey, IDKey>> getRegistry() { 121 return REGISTRY.get(); 122 } 123 124 /** 125 * <p> 126 * Converters value pair into a register pair. 127 * </p> 128 * 129 * @param lhs <code>this</code> object 130 * @param rhs the other object 131 * 132 * @return the pair 133 */ 134 static Pair<IDKey, IDKey> getRegisterPair(Object lhs, Object rhs) { 135 IDKey left = new IDKey(lhs); 136 IDKey right = new IDKey(rhs); 137 return Pair.of(left, right); 138 } 139 140 /** 141 * <p> 142 * Returns <code>true</code> if the registry contains the given object pair. 143 * Used by the reflection methods to avoid infinite loops. 144 * Objects might be swapped therefore a check is needed if the object pair 145 * is registered in given or swapped order. 146 * </p> 147 * 148 * @param lhs <code>this</code> object to lookup in registry 149 * @param rhs the other object to lookup on registry 150 * @return boolean <code>true</code> if the registry contains the given object. 151 * @since 3.0 152 */ 153 static boolean isRegistered(Object lhs, Object rhs) { 154 Set<Pair<IDKey, IDKey>> registry = getRegistry(); 155 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); 156 Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getLeft(), pair.getRight()); 157 158 return registry != null 159 && (registry.contains(pair) || registry.contains(swappedPair)); 160 } 161 162 /** 163 * <p> 164 * Registers the given object pair. 165 * Used by the reflection methods to avoid infinite loops. 166 * </p> 167 * 168 * @param lhs <code>this</code> object to register 169 * @param rhs the other object to register 170 */ 171 static void register(Object lhs, Object rhs) { 172 synchronized (EqualsBuilder.class) { 173 if (getRegistry() == null) { 174 REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>()); 175 } 176 } 177 178 Set<Pair<IDKey, IDKey>> registry = getRegistry(); 179 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); 180 registry.add(pair); 181 } 182 183 /** 184 * <p> 185 * Unregisters the given object pair. 186 * </p> 187 * 188 * <p> 189 * Used by the reflection methods to avoid infinite loops. 190 * 191 * @param lhs <code>this</code> object to unregister 192 * @param rhs the other object to unregister 193 * @since 3.0 194 */ 195 static void unregister(Object lhs, Object rhs) { 196 Set<Pair<IDKey, IDKey>> registry = getRegistry(); 197 if (registry != null) { 198 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); 199 registry.remove(pair); 200 synchronized (EqualsBuilder.class) { 201 //read again 202 registry = getRegistry(); 203 if (registry != null && registry.isEmpty()) { 204 REGISTRY.remove(); 205 } 206 } 207 } 208 } 209 210 /** 211 * If the fields tested are equals. 212 * The default value is <code>true</code>. 213 */ 214 private boolean isEquals = true; 215 216 /** 217 * <p>Constructor for EqualsBuilder.</p> 218 * 219 * <p>Starts off assuming that equals is <code>true</code>.</p> 220 * @see Object#equals(Object) 221 */ 222 public EqualsBuilder() { 223 // do nothing for now. 224 } 225 226 //------------------------------------------------------------------------- 227 228 /** 229 * <p>This method uses reflection to determine if the two <code>Object</code>s 230 * are equal.</p> 231 * 232 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 233 * fields. This means that it will throw a security exception if run under 234 * a security manager, if the permissions are not set up correctly. It is also 235 * not as efficient as testing explicitly.</p> 236 * 237 * <p>Transient members will be not be tested, as they are likely derived 238 * fields, and not part of the value of the Object.</p> 239 * 240 * <p>Static fields will not be tested. Superclass fields will be included.</p> 241 * 242 * @param lhs <code>this</code> object 243 * @param rhs the other object 244 * @param excludeFields Collection of String field names to exclude from testing 245 * @return <code>true</code> if the two Objects have tested equals. 246 */ 247 public static boolean reflectionEquals(Object lhs, Object rhs, Collection<String> excludeFields) { 248 return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); 249 } 250 251 /** 252 * <p>This method uses reflection to determine if the two <code>Object</code>s 253 * are equal.</p> 254 * 255 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 256 * fields. This means that it will throw a security exception if run under 257 * a security manager, if the permissions are not set up correctly. It is also 258 * not as efficient as testing explicitly.</p> 259 * 260 * <p>Transient members will be not be tested, as they are likely derived 261 * fields, and not part of the value of the Object.</p> 262 * 263 * <p>Static fields will not be tested. Superclass fields will be included.</p> 264 * 265 * @param lhs <code>this</code> object 266 * @param rhs the other object 267 * @param excludeFields array of field names to exclude from testing 268 * @return <code>true</code> if the two Objects have tested equals. 269 */ 270 public static boolean reflectionEquals(Object lhs, Object rhs, String... excludeFields) { 271 return reflectionEquals(lhs, rhs, false, null, excludeFields); 272 } 273 274 /** 275 * <p>This method uses reflection to determine if the two <code>Object</code>s 276 * are equal.</p> 277 * 278 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 279 * fields. This means that it will throw a security exception if run under 280 * a security manager, if the permissions are not set up correctly. It is also 281 * not as efficient as testing explicitly.</p> 282 * 283 * <p>If the TestTransients parameter is set to <code>true</code>, transient 284 * members will be tested, otherwise they are ignored, as they are likely 285 * derived fields, and not part of the value of the <code>Object</code>.</p> 286 * 287 * <p>Static fields will not be tested. Superclass fields will be included.</p> 288 * 289 * @param lhs <code>this</code> object 290 * @param rhs the other object 291 * @param testTransients whether to include transient fields 292 * @return <code>true</code> if the two Objects have tested equals. 293 */ 294 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) { 295 return reflectionEquals(lhs, rhs, testTransients, null); 296 } 297 298 /** 299 * <p>This method uses reflection to determine if the two <code>Object</code>s 300 * are equal.</p> 301 * 302 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 303 * fields. This means that it will throw a security exception if run under 304 * a security manager, if the permissions are not set up correctly. It is also 305 * not as efficient as testing explicitly.</p> 306 * 307 * <p>If the testTransients parameter is set to <code>true</code>, transient 308 * members will be tested, otherwise they are ignored, as they are likely 309 * derived fields, and not part of the value of the <code>Object</code>.</p> 310 * 311 * <p>Static fields will not be included. Superclass fields will be appended 312 * up to and including the specified superclass. A null superclass is treated 313 * as java.lang.Object.</p> 314 * 315 * @param lhs <code>this</code> object 316 * @param rhs the other object 317 * @param testTransients whether to include transient fields 318 * @param reflectUpToClass the superclass to reflect up to (inclusive), 319 * may be <code>null</code> 320 * @param excludeFields array of field names to exclude from testing 321 * @return <code>true</code> if the two Objects have tested equals. 322 * @since 2.0 323 */ 324 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass, 325 String... excludeFields) { 326 if (lhs == rhs) { 327 return true; 328 } 329 if (lhs == null || rhs == null) { 330 return false; 331 } 332 // Find the leaf class since there may be transients in the leaf 333 // class or in classes between the leaf and root. 334 // If we are not testing transients or a subclass has no ivars, 335 // then a subclass can test equals to a superclass. 336 Class<?> lhsClass = lhs.getClass(); 337 Class<?> rhsClass = rhs.getClass(); 338 Class<?> testClass; 339 if (lhsClass.isInstance(rhs)) { 340 testClass = lhsClass; 341 if (!rhsClass.isInstance(lhs)) { 342 // rhsClass is a subclass of lhsClass 343 testClass = rhsClass; 344 } 345 } else if (rhsClass.isInstance(lhs)) { 346 testClass = rhsClass; 347 if (!lhsClass.isInstance(rhs)) { 348 // lhsClass is a subclass of rhsClass 349 testClass = lhsClass; 350 } 351 } else { 352 // The two classes are not related. 353 return false; 354 } 355 EqualsBuilder equalsBuilder = new EqualsBuilder(); 356 try { 357 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields); 358 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) { 359 testClass = testClass.getSuperclass(); 360 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields); 361 } 362 } catch (IllegalArgumentException e) { 363 // In this case, we tried to test a subclass vs. a superclass and 364 // the subclass has ivars or the ivars are transient and 365 // we are testing transients. 366 // If a subclass has ivars that we are trying to test them, we get an 367 // exception and we know that the objects are not equal. 368 return false; 369 } 370 return equalsBuilder.isEquals(); 371 } 372 373 /** 374 * <p>Appends the fields and values defined by the given object of the 375 * given Class.</p> 376 * 377 * @param lhs the left hand object 378 * @param rhs the right hand object 379 * @param clazz the class to append details of 380 * @param builder the builder to append to 381 * @param useTransients whether to test transient fields 382 * @param excludeFields array of field names to exclude from testing 383 */ 384 private static void reflectionAppend( 385 Object lhs, 386 Object rhs, 387 Class<?> clazz, 388 EqualsBuilder builder, 389 boolean useTransients, 390 String[] excludeFields) { 391 392 if (isRegistered(lhs, rhs)) { 393 return; 394 } 395 396 try { 397 register(lhs, rhs); 398 Field[] fields = clazz.getDeclaredFields(); 399 AccessibleObject.setAccessible(fields, true); 400 for (int i = 0; i < fields.length && builder.isEquals; i++) { 401 Field f = fields[i]; 402 if (!ArrayUtils.contains(excludeFields, f.getName()) 403 && (f.getName().indexOf('$') == -1) 404 && (useTransients || !Modifier.isTransient(f.getModifiers())) 405 && (!Modifier.isStatic(f.getModifiers()))) { 406 try { 407 builder.append(f.get(lhs), f.get(rhs)); 408 } catch (IllegalAccessException e) { 409 //this can't happen. Would get a Security exception instead 410 //throw a runtime exception in case the impossible happens. 411 throw new InternalError("Unexpected IllegalAccessException"); 412 } 413 } 414 } 415 } finally { 416 unregister(lhs, rhs); 417 } 418 } 419 420 //------------------------------------------------------------------------- 421 422 /** 423 * <p>Adds the result of <code>super.equals()</code> to this builder.</p> 424 * 425 * @param superEquals the result of calling <code>super.equals()</code> 426 * @return EqualsBuilder - used to chain calls. 427 * @since 2.0 428 */ 429 public EqualsBuilder appendSuper(boolean superEquals) { 430 if (isEquals == false) { 431 return this; 432 } 433 isEquals = superEquals; 434 return this; 435 } 436 437 //------------------------------------------------------------------------- 438 439 /** 440 * <p>Test if two <code>Object</code>s are equal using their 441 * <code>equals</code> method.</p> 442 * 443 * @param lhs the left hand object 444 * @param rhs the right hand object 445 * @return EqualsBuilder - used to chain calls. 446 */ 447 public EqualsBuilder append(Object lhs, Object rhs) { 448 if (isEquals == false) { 449 return this; 450 } 451 if (lhs == rhs) { 452 return this; 453 } 454 if (lhs == null || rhs == null) { 455 this.setEquals(false); 456 return this; 457 } 458 Class<?> lhsClass = lhs.getClass(); 459 if (!lhsClass.isArray()) { 460 // The simple case, not an array, just test the element 461 isEquals = lhs.equals(rhs); 462 } else if (lhs.getClass() != rhs.getClass()) { 463 // Here when we compare different dimensions, for example: a boolean[][] to a boolean[] 464 this.setEquals(false); 465 } 466 // 'Switch' on type of array, to dispatch to the correct handler 467 // This handles multi dimensional arrays of the same depth 468 else if (lhs instanceof long[]) { 469 append((long[]) lhs, (long[]) rhs); 470 } else if (lhs instanceof int[]) { 471 append((int[]) lhs, (int[]) rhs); 472 } else if (lhs instanceof short[]) { 473 append((short[]) lhs, (short[]) rhs); 474 } else if (lhs instanceof char[]) { 475 append((char[]) lhs, (char[]) rhs); 476 } else if (lhs instanceof byte[]) { 477 append((byte[]) lhs, (byte[]) rhs); 478 } else if (lhs instanceof double[]) { 479 append((double[]) lhs, (double[]) rhs); 480 } else if (lhs instanceof float[]) { 481 append((float[]) lhs, (float[]) rhs); 482 } else if (lhs instanceof boolean[]) { 483 append((boolean[]) lhs, (boolean[]) rhs); 484 } else { 485 // Not an array of primitives 486 append((Object[]) lhs, (Object[]) rhs); 487 } 488 return this; 489 } 490 491 /** 492 * <p> 493 * Test if two <code>long</code> s are equal. 494 * </p> 495 * 496 * @param lhs 497 * the left hand <code>long</code> 498 * @param rhs 499 * the right hand <code>long</code> 500 * @return EqualsBuilder - used to chain calls. 501 */ 502 public EqualsBuilder append(long lhs, long rhs) { 503 if (isEquals == false) { 504 return this; 505 } 506 isEquals = (lhs == rhs); 507 return this; 508 } 509 510 /** 511 * <p>Test if two <code>int</code>s are equal.</p> 512 * 513 * @param lhs the left hand <code>int</code> 514 * @param rhs the right hand <code>int</code> 515 * @return EqualsBuilder - used to chain calls. 516 */ 517 public EqualsBuilder append(int lhs, int rhs) { 518 if (isEquals == false) { 519 return this; 520 } 521 isEquals = (lhs == rhs); 522 return this; 523 } 524 525 /** 526 * <p>Test if two <code>short</code>s are equal.</p> 527 * 528 * @param lhs the left hand <code>short</code> 529 * @param rhs the right hand <code>short</code> 530 * @return EqualsBuilder - used to chain calls. 531 */ 532 public EqualsBuilder append(short lhs, short rhs) { 533 if (isEquals == false) { 534 return this; 535 } 536 isEquals = (lhs == rhs); 537 return this; 538 } 539 540 /** 541 * <p>Test if two <code>char</code>s are equal.</p> 542 * 543 * @param lhs the left hand <code>char</code> 544 * @param rhs the right hand <code>char</code> 545 * @return EqualsBuilder - used to chain calls. 546 */ 547 public EqualsBuilder append(char lhs, char rhs) { 548 if (isEquals == false) { 549 return this; 550 } 551 isEquals = (lhs == rhs); 552 return this; 553 } 554 555 /** 556 * <p>Test if two <code>byte</code>s are equal.</p> 557 * 558 * @param lhs the left hand <code>byte</code> 559 * @param rhs the right hand <code>byte</code> 560 * @return EqualsBuilder - used to chain calls. 561 */ 562 public EqualsBuilder append(byte lhs, byte rhs) { 563 if (isEquals == false) { 564 return this; 565 } 566 isEquals = (lhs == rhs); 567 return this; 568 } 569 570 /** 571 * <p>Test if two <code>double</code>s are equal by testing that the 572 * pattern of bits returned by <code>doubleToLong</code> are equal.</p> 573 * 574 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 575 * 576 * <p>It is compatible with the hash code generated by 577 * <code>HashCodeBuilder</code>.</p> 578 * 579 * @param lhs the left hand <code>double</code> 580 * @param rhs the right hand <code>double</code> 581 * @return EqualsBuilder - used to chain calls. 582 */ 583 public EqualsBuilder append(double lhs, double rhs) { 584 if (isEquals == false) { 585 return this; 586 } 587 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs)); 588 } 589 590 /** 591 * <p>Test if two <code>float</code>s are equal byt testing that the 592 * pattern of bits returned by doubleToLong are equal.</p> 593 * 594 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 595 * 596 * <p>It is compatible with the hash code generated by 597 * <code>HashCodeBuilder</code>.</p> 598 * 599 * @param lhs the left hand <code>float</code> 600 * @param rhs the right hand <code>float</code> 601 * @return EqualsBuilder - used to chain calls. 602 */ 603 public EqualsBuilder append(float lhs, float rhs) { 604 if (isEquals == false) { 605 return this; 606 } 607 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs)); 608 } 609 610 /** 611 * <p>Test if two <code>booleans</code>s are equal.</p> 612 * 613 * @param lhs the left hand <code>boolean</code> 614 * @param rhs the right hand <code>boolean</code> 615 * @return EqualsBuilder - used to chain calls. 616 */ 617 public EqualsBuilder append(boolean lhs, boolean rhs) { 618 if (isEquals == false) { 619 return this; 620 } 621 isEquals = (lhs == rhs); 622 return this; 623 } 624 625 /** 626 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p> 627 * 628 * <p>This also will be called for the top level of 629 * multi-dimensional, ragged, and multi-typed arrays.</p> 630 * 631 * @param lhs the left hand <code>Object[]</code> 632 * @param rhs the right hand <code>Object[]</code> 633 * @return EqualsBuilder - used to chain calls. 634 */ 635 public EqualsBuilder append(Object[] lhs, Object[] rhs) { 636 if (isEquals == false) { 637 return this; 638 } 639 if (lhs == rhs) { 640 return this; 641 } 642 if (lhs == null || rhs == null) { 643 this.setEquals(false); 644 return this; 645 } 646 if (lhs.length != rhs.length) { 647 this.setEquals(false); 648 return this; 649 } 650 for (int i = 0; i < lhs.length && isEquals; ++i) { 651 append(lhs[i], rhs[i]); 652 } 653 return this; 654 } 655 656 /** 657 * <p>Deep comparison of array of <code>long</code>. Length and all 658 * values are compared.</p> 659 * 660 * <p>The method {@link #append(long, long)} is used.</p> 661 * 662 * @param lhs the left hand <code>long[]</code> 663 * @param rhs the right hand <code>long[]</code> 664 * @return EqualsBuilder - used to chain calls. 665 */ 666 public EqualsBuilder append(long[] lhs, long[] rhs) { 667 if (isEquals == false) { 668 return this; 669 } 670 if (lhs == rhs) { 671 return this; 672 } 673 if (lhs == null || rhs == null) { 674 this.setEquals(false); 675 return this; 676 } 677 if (lhs.length != rhs.length) { 678 this.setEquals(false); 679 return this; 680 } 681 for (int i = 0; i < lhs.length && isEquals; ++i) { 682 append(lhs[i], rhs[i]); 683 } 684 return this; 685 } 686 687 /** 688 * <p>Deep comparison of array of <code>int</code>. Length and all 689 * values are compared.</p> 690 * 691 * <p>The method {@link #append(int, int)} is used.</p> 692 * 693 * @param lhs the left hand <code>int[]</code> 694 * @param rhs the right hand <code>int[]</code> 695 * @return EqualsBuilder - used to chain calls. 696 */ 697 public EqualsBuilder append(int[] lhs, int[] rhs) { 698 if (isEquals == false) { 699 return this; 700 } 701 if (lhs == rhs) { 702 return this; 703 } 704 if (lhs == null || rhs == null) { 705 this.setEquals(false); 706 return this; 707 } 708 if (lhs.length != rhs.length) { 709 this.setEquals(false); 710 return this; 711 } 712 for (int i = 0; i < lhs.length && isEquals; ++i) { 713 append(lhs[i], rhs[i]); 714 } 715 return this; 716 } 717 718 /** 719 * <p>Deep comparison of array of <code>short</code>. Length and all 720 * values are compared.</p> 721 * 722 * <p>The method {@link #append(short, short)} is used.</p> 723 * 724 * @param lhs the left hand <code>short[]</code> 725 * @param rhs the right hand <code>short[]</code> 726 * @return EqualsBuilder - used to chain calls. 727 */ 728 public EqualsBuilder append(short[] lhs, short[] rhs) { 729 if (isEquals == false) { 730 return this; 731 } 732 if (lhs == rhs) { 733 return this; 734 } 735 if (lhs == null || rhs == null) { 736 this.setEquals(false); 737 return this; 738 } 739 if (lhs.length != rhs.length) { 740 this.setEquals(false); 741 return this; 742 } 743 for (int i = 0; i < lhs.length && isEquals; ++i) { 744 append(lhs[i], rhs[i]); 745 } 746 return this; 747 } 748 749 /** 750 * <p>Deep comparison of array of <code>char</code>. Length and all 751 * values are compared.</p> 752 * 753 * <p>The method {@link #append(char, char)} is used.</p> 754 * 755 * @param lhs the left hand <code>char[]</code> 756 * @param rhs the right hand <code>char[]</code> 757 * @return EqualsBuilder - used to chain calls. 758 */ 759 public EqualsBuilder append(char[] lhs, char[] rhs) { 760 if (isEquals == false) { 761 return this; 762 } 763 if (lhs == rhs) { 764 return this; 765 } 766 if (lhs == null || rhs == null) { 767 this.setEquals(false); 768 return this; 769 } 770 if (lhs.length != rhs.length) { 771 this.setEquals(false); 772 return this; 773 } 774 for (int i = 0; i < lhs.length && isEquals; ++i) { 775 append(lhs[i], rhs[i]); 776 } 777 return this; 778 } 779 780 /** 781 * <p>Deep comparison of array of <code>byte</code>. Length and all 782 * values are compared.</p> 783 * 784 * <p>The method {@link #append(byte, byte)} is used.</p> 785 * 786 * @param lhs the left hand <code>byte[]</code> 787 * @param rhs the right hand <code>byte[]</code> 788 * @return EqualsBuilder - used to chain calls. 789 */ 790 public EqualsBuilder append(byte[] lhs, byte[] rhs) { 791 if (isEquals == false) { 792 return this; 793 } 794 if (lhs == rhs) { 795 return this; 796 } 797 if (lhs == null || rhs == null) { 798 this.setEquals(false); 799 return this; 800 } 801 if (lhs.length != rhs.length) { 802 this.setEquals(false); 803 return this; 804 } 805 for (int i = 0; i < lhs.length && isEquals; ++i) { 806 append(lhs[i], rhs[i]); 807 } 808 return this; 809 } 810 811 /** 812 * <p>Deep comparison of array of <code>double</code>. Length and all 813 * values are compared.</p> 814 * 815 * <p>The method {@link #append(double, double)} is used.</p> 816 * 817 * @param lhs the left hand <code>double[]</code> 818 * @param rhs the right hand <code>double[]</code> 819 * @return EqualsBuilder - used to chain calls. 820 */ 821 public EqualsBuilder append(double[] lhs, double[] rhs) { 822 if (isEquals == false) { 823 return this; 824 } 825 if (lhs == rhs) { 826 return this; 827 } 828 if (lhs == null || rhs == null) { 829 this.setEquals(false); 830 return this; 831 } 832 if (lhs.length != rhs.length) { 833 this.setEquals(false); 834 return this; 835 } 836 for (int i = 0; i < lhs.length && isEquals; ++i) { 837 append(lhs[i], rhs[i]); 838 } 839 return this; 840 } 841 842 /** 843 * <p>Deep comparison of array of <code>float</code>. Length and all 844 * values are compared.</p> 845 * 846 * <p>The method {@link #append(float, float)} is used.</p> 847 * 848 * @param lhs the left hand <code>float[]</code> 849 * @param rhs the right hand <code>float[]</code> 850 * @return EqualsBuilder - used to chain calls. 851 */ 852 public EqualsBuilder append(float[] lhs, float[] rhs) { 853 if (isEquals == false) { 854 return this; 855 } 856 if (lhs == rhs) { 857 return this; 858 } 859 if (lhs == null || rhs == null) { 860 this.setEquals(false); 861 return this; 862 } 863 if (lhs.length != rhs.length) { 864 this.setEquals(false); 865 return this; 866 } 867 for (int i = 0; i < lhs.length && isEquals; ++i) { 868 append(lhs[i], rhs[i]); 869 } 870 return this; 871 } 872 873 /** 874 * <p>Deep comparison of array of <code>boolean</code>. Length and all 875 * values are compared.</p> 876 * 877 * <p>The method {@link #append(boolean, boolean)} is used.</p> 878 * 879 * @param lhs the left hand <code>boolean[]</code> 880 * @param rhs the right hand <code>boolean[]</code> 881 * @return EqualsBuilder - used to chain calls. 882 */ 883 public EqualsBuilder append(boolean[] lhs, boolean[] rhs) { 884 if (isEquals == false) { 885 return this; 886 } 887 if (lhs == rhs) { 888 return this; 889 } 890 if (lhs == null || rhs == null) { 891 this.setEquals(false); 892 return this; 893 } 894 if (lhs.length != rhs.length) { 895 this.setEquals(false); 896 return this; 897 } 898 for (int i = 0; i < lhs.length && isEquals; ++i) { 899 append(lhs[i], rhs[i]); 900 } 901 return this; 902 } 903 904 /** 905 * <p>Returns <code>true</code> if the fields that have been checked 906 * are all equal.</p> 907 * 908 * @return boolean 909 */ 910 public boolean isEquals() { 911 return this.isEquals; 912 } 913 914 /** 915 * <p>Returns <code>true</code> if the fields that have been checked 916 * are all equal.</p> 917 * 918 * @return <code>true</code> if all of the fields that have been checked 919 * are equal, <code>false</code> otherwise. 920 * 921 * @since 3.0 922 */ 923 public Boolean build() { 924 return Boolean.valueOf(isEquals()); 925 } 926 927 /** 928 * Sets the <code>isEquals</code> value. 929 * 930 * @param isEquals The value to set. 931 * @since 2.1 932 */ 933 protected void setEquals(boolean isEquals) { 934 this.isEquals = isEquals; 935 } 936 937 /** 938 * Reset the EqualsBuilder so you can use the same object again 939 * @since 2.5 940 */ 941 public void reset() { 942 this.isEquals = true; 943 } 944 }