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 */ 017package org.apache.commons.lang3.builder; 018 019import java.lang.reflect.AccessibleObject; 020import java.lang.reflect.Field; 021import java.lang.reflect.Modifier; 022import java.util.Collection; 023import java.util.HashSet; 024import java.util.Set; 025 026import org.apache.commons.lang3.ArrayUtils; 027import 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://www.oracle.com/technetwork/java/effectivejava-136174.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 1535757 2013-10-25 15:07:13Z mbenson $ 082 */ 083public 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(final Object lhs, final Object rhs) { 135 final IDKey left = new IDKey(lhs); 136 final 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(final Object lhs, final Object rhs) { 154 final Set<Pair<IDKey, IDKey>> registry = getRegistry(); 155 final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); 156 final 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(final Object lhs, final Object rhs) { 172 synchronized (EqualsBuilder.class) { 173 if (getRegistry() == null) { 174 REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>()); 175 } 176 } 177 178 final Set<Pair<IDKey, IDKey>> registry = getRegistry(); 179 final 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(final Object lhs, final Object rhs) { 196 Set<Pair<IDKey, IDKey>> registry = getRegistry(); 197 if (registry != null) { 198 final 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(final Object lhs, final Object rhs, final 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(final Object lhs, final Object rhs, final 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(final Object lhs, final Object rhs, final 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(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass, 325 final 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 final Class<?> lhsClass = lhs.getClass(); 337 final 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 final EqualsBuilder equalsBuilder = new EqualsBuilder(); 356 try { 357 if (testClass.isArray()) { 358 equalsBuilder.append(lhs, rhs); 359 } else { 360 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields); 361 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) { 362 testClass = testClass.getSuperclass(); 363 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields); 364 } 365 } 366 } catch (final IllegalArgumentException e) { 367 // In this case, we tried to test a subclass vs. a superclass and 368 // the subclass has ivars or the ivars are transient and 369 // we are testing transients. 370 // If a subclass has ivars that we are trying to test them, we get an 371 // exception and we know that the objects are not equal. 372 return false; 373 } 374 return equalsBuilder.isEquals(); 375 } 376 377 /** 378 * <p>Appends the fields and values defined by the given object of the 379 * given Class.</p> 380 * 381 * @param lhs the left hand object 382 * @param rhs the right hand object 383 * @param clazz the class to append details of 384 * @param builder the builder to append to 385 * @param useTransients whether to test transient fields 386 * @param excludeFields array of field names to exclude from testing 387 */ 388 private static void reflectionAppend( 389 final Object lhs, 390 final Object rhs, 391 final Class<?> clazz, 392 final EqualsBuilder builder, 393 final boolean useTransients, 394 final String[] excludeFields) { 395 396 if (isRegistered(lhs, rhs)) { 397 return; 398 } 399 400 try { 401 register(lhs, rhs); 402 final Field[] fields = clazz.getDeclaredFields(); 403 AccessibleObject.setAccessible(fields, true); 404 for (int i = 0; i < fields.length && builder.isEquals; i++) { 405 final Field f = fields[i]; 406 if (!ArrayUtils.contains(excludeFields, f.getName()) 407 && (f.getName().indexOf('$') == -1) 408 && (useTransients || !Modifier.isTransient(f.getModifiers())) 409 && (!Modifier.isStatic(f.getModifiers()))) { 410 try { 411 builder.append(f.get(lhs), f.get(rhs)); 412 } catch (final IllegalAccessException e) { 413 //this can't happen. Would get a Security exception instead 414 //throw a runtime exception in case the impossible happens. 415 throw new InternalError("Unexpected IllegalAccessException"); 416 } 417 } 418 } 419 } finally { 420 unregister(lhs, rhs); 421 } 422 } 423 424 //------------------------------------------------------------------------- 425 426 /** 427 * <p>Adds the result of <code>super.equals()</code> to this builder.</p> 428 * 429 * @param superEquals the result of calling <code>super.equals()</code> 430 * @return EqualsBuilder - used to chain calls. 431 * @since 2.0 432 */ 433 public EqualsBuilder appendSuper(final boolean superEquals) { 434 if (isEquals == false) { 435 return this; 436 } 437 isEquals = superEquals; 438 return this; 439 } 440 441 //------------------------------------------------------------------------- 442 443 /** 444 * <p>Test if two <code>Object</code>s are equal using their 445 * <code>equals</code> method.</p> 446 * 447 * @param lhs the left hand object 448 * @param rhs the right hand object 449 * @return EqualsBuilder - used to chain calls. 450 */ 451 public EqualsBuilder append(final Object lhs, final Object rhs) { 452 if (isEquals == false) { 453 return this; 454 } 455 if (lhs == rhs) { 456 return this; 457 } 458 if (lhs == null || rhs == null) { 459 this.setEquals(false); 460 return this; 461 } 462 final Class<?> lhsClass = lhs.getClass(); 463 if (!lhsClass.isArray()) { 464 // The simple case, not an array, just test the element 465 isEquals = lhs.equals(rhs); 466 } else if (lhs.getClass() != rhs.getClass()) { 467 // Here when we compare different dimensions, for example: a boolean[][] to a boolean[] 468 this.setEquals(false); 469 } 470 // 'Switch' on type of array, to dispatch to the correct handler 471 // This handles multi dimensional arrays of the same depth 472 else if (lhs instanceof long[]) { 473 append((long[]) lhs, (long[]) rhs); 474 } else if (lhs instanceof int[]) { 475 append((int[]) lhs, (int[]) rhs); 476 } else if (lhs instanceof short[]) { 477 append((short[]) lhs, (short[]) rhs); 478 } else if (lhs instanceof char[]) { 479 append((char[]) lhs, (char[]) rhs); 480 } else if (lhs instanceof byte[]) { 481 append((byte[]) lhs, (byte[]) rhs); 482 } else if (lhs instanceof double[]) { 483 append((double[]) lhs, (double[]) rhs); 484 } else if (lhs instanceof float[]) { 485 append((float[]) lhs, (float[]) rhs); 486 } else if (lhs instanceof boolean[]) { 487 append((boolean[]) lhs, (boolean[]) rhs); 488 } else { 489 // Not an array of primitives 490 append((Object[]) lhs, (Object[]) rhs); 491 } 492 return this; 493 } 494 495 /** 496 * <p> 497 * Test if two <code>long</code> s are equal. 498 * </p> 499 * 500 * @param lhs 501 * the left hand <code>long</code> 502 * @param rhs 503 * the right hand <code>long</code> 504 * @return EqualsBuilder - used to chain calls. 505 */ 506 public EqualsBuilder append(final long lhs, final long rhs) { 507 if (isEquals == false) { 508 return this; 509 } 510 isEquals = (lhs == rhs); 511 return this; 512 } 513 514 /** 515 * <p>Test if two <code>int</code>s are equal.</p> 516 * 517 * @param lhs the left hand <code>int</code> 518 * @param rhs the right hand <code>int</code> 519 * @return EqualsBuilder - used to chain calls. 520 */ 521 public EqualsBuilder append(final int lhs, final int rhs) { 522 if (isEquals == false) { 523 return this; 524 } 525 isEquals = (lhs == rhs); 526 return this; 527 } 528 529 /** 530 * <p>Test if two <code>short</code>s are equal.</p> 531 * 532 * @param lhs the left hand <code>short</code> 533 * @param rhs the right hand <code>short</code> 534 * @return EqualsBuilder - used to chain calls. 535 */ 536 public EqualsBuilder append(final short lhs, final short rhs) { 537 if (isEquals == false) { 538 return this; 539 } 540 isEquals = (lhs == rhs); 541 return this; 542 } 543 544 /** 545 * <p>Test if two <code>char</code>s are equal.</p> 546 * 547 * @param lhs the left hand <code>char</code> 548 * @param rhs the right hand <code>char</code> 549 * @return EqualsBuilder - used to chain calls. 550 */ 551 public EqualsBuilder append(final char lhs, final char rhs) { 552 if (isEquals == false) { 553 return this; 554 } 555 isEquals = (lhs == rhs); 556 return this; 557 } 558 559 /** 560 * <p>Test if two <code>byte</code>s are equal.</p> 561 * 562 * @param lhs the left hand <code>byte</code> 563 * @param rhs the right hand <code>byte</code> 564 * @return EqualsBuilder - used to chain calls. 565 */ 566 public EqualsBuilder append(final byte lhs, final byte rhs) { 567 if (isEquals == false) { 568 return this; 569 } 570 isEquals = (lhs == rhs); 571 return this; 572 } 573 574 /** 575 * <p>Test if two <code>double</code>s are equal by testing that the 576 * pattern of bits returned by <code>doubleToLong</code> are equal.</p> 577 * 578 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 579 * 580 * <p>It is compatible with the hash code generated by 581 * <code>HashCodeBuilder</code>.</p> 582 * 583 * @param lhs the left hand <code>double</code> 584 * @param rhs the right hand <code>double</code> 585 * @return EqualsBuilder - used to chain calls. 586 */ 587 public EqualsBuilder append(final double lhs, final double rhs) { 588 if (isEquals == false) { 589 return this; 590 } 591 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs)); 592 } 593 594 /** 595 * <p>Test if two <code>float</code>s are equal byt testing that the 596 * pattern of bits returned by doubleToLong are equal.</p> 597 * 598 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 599 * 600 * <p>It is compatible with the hash code generated by 601 * <code>HashCodeBuilder</code>.</p> 602 * 603 * @param lhs the left hand <code>float</code> 604 * @param rhs the right hand <code>float</code> 605 * @return EqualsBuilder - used to chain calls. 606 */ 607 public EqualsBuilder append(final float lhs, final float rhs) { 608 if (isEquals == false) { 609 return this; 610 } 611 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs)); 612 } 613 614 /** 615 * <p>Test if two <code>booleans</code>s are equal.</p> 616 * 617 * @param lhs the left hand <code>boolean</code> 618 * @param rhs the right hand <code>boolean</code> 619 * @return EqualsBuilder - used to chain calls. 620 */ 621 public EqualsBuilder append(final boolean lhs, final boolean rhs) { 622 if (isEquals == false) { 623 return this; 624 } 625 isEquals = (lhs == rhs); 626 return this; 627 } 628 629 /** 630 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p> 631 * 632 * <p>This also will be called for the top level of 633 * multi-dimensional, ragged, and multi-typed arrays.</p> 634 * 635 * @param lhs the left hand <code>Object[]</code> 636 * @param rhs the right hand <code>Object[]</code> 637 * @return EqualsBuilder - used to chain calls. 638 */ 639 public EqualsBuilder append(final Object[] lhs, final Object[] rhs) { 640 if (isEquals == false) { 641 return this; 642 } 643 if (lhs == rhs) { 644 return this; 645 } 646 if (lhs == null || rhs == null) { 647 this.setEquals(false); 648 return this; 649 } 650 if (lhs.length != rhs.length) { 651 this.setEquals(false); 652 return this; 653 } 654 for (int i = 0; i < lhs.length && isEquals; ++i) { 655 append(lhs[i], rhs[i]); 656 } 657 return this; 658 } 659 660 /** 661 * <p>Deep comparison of array of <code>long</code>. Length and all 662 * values are compared.</p> 663 * 664 * <p>The method {@link #append(long, long)} is used.</p> 665 * 666 * @param lhs the left hand <code>long[]</code> 667 * @param rhs the right hand <code>long[]</code> 668 * @return EqualsBuilder - used to chain calls. 669 */ 670 public EqualsBuilder append(final long[] lhs, final long[] rhs) { 671 if (isEquals == false) { 672 return this; 673 } 674 if (lhs == rhs) { 675 return this; 676 } 677 if (lhs == null || rhs == null) { 678 this.setEquals(false); 679 return this; 680 } 681 if (lhs.length != rhs.length) { 682 this.setEquals(false); 683 return this; 684 } 685 for (int i = 0; i < lhs.length && isEquals; ++i) { 686 append(lhs[i], rhs[i]); 687 } 688 return this; 689 } 690 691 /** 692 * <p>Deep comparison of array of <code>int</code>. Length and all 693 * values are compared.</p> 694 * 695 * <p>The method {@link #append(int, int)} is used.</p> 696 * 697 * @param lhs the left hand <code>int[]</code> 698 * @param rhs the right hand <code>int[]</code> 699 * @return EqualsBuilder - used to chain calls. 700 */ 701 public EqualsBuilder append(final int[] lhs, final int[] rhs) { 702 if (isEquals == false) { 703 return this; 704 } 705 if (lhs == rhs) { 706 return this; 707 } 708 if (lhs == null || rhs == null) { 709 this.setEquals(false); 710 return this; 711 } 712 if (lhs.length != rhs.length) { 713 this.setEquals(false); 714 return this; 715 } 716 for (int i = 0; i < lhs.length && isEquals; ++i) { 717 append(lhs[i], rhs[i]); 718 } 719 return this; 720 } 721 722 /** 723 * <p>Deep comparison of array of <code>short</code>. Length and all 724 * values are compared.</p> 725 * 726 * <p>The method {@link #append(short, short)} is used.</p> 727 * 728 * @param lhs the left hand <code>short[]</code> 729 * @param rhs the right hand <code>short[]</code> 730 * @return EqualsBuilder - used to chain calls. 731 */ 732 public EqualsBuilder append(final short[] lhs, final short[] rhs) { 733 if (isEquals == false) { 734 return this; 735 } 736 if (lhs == rhs) { 737 return this; 738 } 739 if (lhs == null || rhs == null) { 740 this.setEquals(false); 741 return this; 742 } 743 if (lhs.length != rhs.length) { 744 this.setEquals(false); 745 return this; 746 } 747 for (int i = 0; i < lhs.length && isEquals; ++i) { 748 append(lhs[i], rhs[i]); 749 } 750 return this; 751 } 752 753 /** 754 * <p>Deep comparison of array of <code>char</code>. Length and all 755 * values are compared.</p> 756 * 757 * <p>The method {@link #append(char, char)} is used.</p> 758 * 759 * @param lhs the left hand <code>char[]</code> 760 * @param rhs the right hand <code>char[]</code> 761 * @return EqualsBuilder - used to chain calls. 762 */ 763 public EqualsBuilder append(final char[] lhs, final char[] rhs) { 764 if (isEquals == false) { 765 return this; 766 } 767 if (lhs == rhs) { 768 return this; 769 } 770 if (lhs == null || rhs == null) { 771 this.setEquals(false); 772 return this; 773 } 774 if (lhs.length != rhs.length) { 775 this.setEquals(false); 776 return this; 777 } 778 for (int i = 0; i < lhs.length && isEquals; ++i) { 779 append(lhs[i], rhs[i]); 780 } 781 return this; 782 } 783 784 /** 785 * <p>Deep comparison of array of <code>byte</code>. Length and all 786 * values are compared.</p> 787 * 788 * <p>The method {@link #append(byte, byte)} is used.</p> 789 * 790 * @param lhs the left hand <code>byte[]</code> 791 * @param rhs the right hand <code>byte[]</code> 792 * @return EqualsBuilder - used to chain calls. 793 */ 794 public EqualsBuilder append(final byte[] lhs, final byte[] rhs) { 795 if (isEquals == false) { 796 return this; 797 } 798 if (lhs == rhs) { 799 return this; 800 } 801 if (lhs == null || rhs == null) { 802 this.setEquals(false); 803 return this; 804 } 805 if (lhs.length != rhs.length) { 806 this.setEquals(false); 807 return this; 808 } 809 for (int i = 0; i < lhs.length && isEquals; ++i) { 810 append(lhs[i], rhs[i]); 811 } 812 return this; 813 } 814 815 /** 816 * <p>Deep comparison of array of <code>double</code>. Length and all 817 * values are compared.</p> 818 * 819 * <p>The method {@link #append(double, double)} is used.</p> 820 * 821 * @param lhs the left hand <code>double[]</code> 822 * @param rhs the right hand <code>double[]</code> 823 * @return EqualsBuilder - used to chain calls. 824 */ 825 public EqualsBuilder append(final double[] lhs, final double[] rhs) { 826 if (isEquals == false) { 827 return this; 828 } 829 if (lhs == rhs) { 830 return this; 831 } 832 if (lhs == null || rhs == null) { 833 this.setEquals(false); 834 return this; 835 } 836 if (lhs.length != rhs.length) { 837 this.setEquals(false); 838 return this; 839 } 840 for (int i = 0; i < lhs.length && isEquals; ++i) { 841 append(lhs[i], rhs[i]); 842 } 843 return this; 844 } 845 846 /** 847 * <p>Deep comparison of array of <code>float</code>. Length and all 848 * values are compared.</p> 849 * 850 * <p>The method {@link #append(float, float)} is used.</p> 851 * 852 * @param lhs the left hand <code>float[]</code> 853 * @param rhs the right hand <code>float[]</code> 854 * @return EqualsBuilder - used to chain calls. 855 */ 856 public EqualsBuilder append(final float[] lhs, final float[] rhs) { 857 if (isEquals == false) { 858 return this; 859 } 860 if (lhs == rhs) { 861 return this; 862 } 863 if (lhs == null || rhs == null) { 864 this.setEquals(false); 865 return this; 866 } 867 if (lhs.length != rhs.length) { 868 this.setEquals(false); 869 return this; 870 } 871 for (int i = 0; i < lhs.length && isEquals; ++i) { 872 append(lhs[i], rhs[i]); 873 } 874 return this; 875 } 876 877 /** 878 * <p>Deep comparison of array of <code>boolean</code>. Length and all 879 * values are compared.</p> 880 * 881 * <p>The method {@link #append(boolean, boolean)} is used.</p> 882 * 883 * @param lhs the left hand <code>boolean[]</code> 884 * @param rhs the right hand <code>boolean[]</code> 885 * @return EqualsBuilder - used to chain calls. 886 */ 887 public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) { 888 if (isEquals == false) { 889 return this; 890 } 891 if (lhs == rhs) { 892 return this; 893 } 894 if (lhs == null || rhs == null) { 895 this.setEquals(false); 896 return this; 897 } 898 if (lhs.length != rhs.length) { 899 this.setEquals(false); 900 return this; 901 } 902 for (int i = 0; i < lhs.length && isEquals; ++i) { 903 append(lhs[i], rhs[i]); 904 } 905 return this; 906 } 907 908 /** 909 * <p>Returns <code>true</code> if the fields that have been checked 910 * are all equal.</p> 911 * 912 * @return boolean 913 */ 914 public boolean isEquals() { 915 return this.isEquals; 916 } 917 918 /** 919 * <p>Returns <code>true</code> if the fields that have been checked 920 * are all equal.</p> 921 * 922 * @return <code>true</code> if all of the fields that have been checked 923 * are equal, <code>false</code> otherwise. 924 * 925 * @since 3.0 926 */ 927 @Override 928 public Boolean build() { 929 return Boolean.valueOf(isEquals()); 930 } 931 932 /** 933 * Sets the <code>isEquals</code> value. 934 * 935 * @param isEquals The value to set. 936 * @since 2.1 937 */ 938 protected void setEquals(final boolean isEquals) { 939 this.isEquals = isEquals; 940 } 941 942 /** 943 * Reset the EqualsBuilder so you can use the same object again 944 * @since 2.5 945 */ 946 public void reset() { 947 this.isEquals = true; 948 } 949}