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