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.ArrayList; 023import java.util.Collection; 024import java.util.HashSet; 025import java.util.List; 026import java.util.Set; 027 028import org.apache.commons.lang3.ArrayUtils; 029import org.apache.commons.lang3.ClassUtils; 030import org.apache.commons.lang3.tuple.Pair; 031 032/** 033 * <p>Assists in implementing {@link Object#equals(Object)} methods.</p> 034 * 035 * <p> This class provides methods to build a good equals method for any 036 * class. It follows rules laid out in 037 * <a href="http://www.oracle.com/technetwork/java/effectivejava-136174.html">Effective Java</a> 038 * , by Joshua Bloch. In particular the rule for comparing {@code doubles}, 039 * {@code floats}, and arrays can be tricky. Also, making sure that 040 * {@code equals()} and {@code hashCode()} are consistent can be 041 * difficult.</p> 042 * 043 * <p>Two Objects that compare as equals must generate the same hash code, 044 * but two Objects with the same hash code do not have to be equal.</p> 045 * 046 * <p>All relevant fields should be included in the calculation of equals. 047 * Derived fields may be ignored. In particular, any field used in 048 * generating a hash code must be used in the equals method, and vice 049 * versa.</p> 050 * 051 * <p>Typical use for the code is as follows:</p> 052 * <pre> 053 * public boolean equals(Object obj) { 054 * if (obj == null) { return false; } 055 * if (obj == this) { return true; } 056 * if (obj.getClass() != getClass()) { 057 * return false; 058 * } 059 * MyClass rhs = (MyClass) obj; 060 * return new EqualsBuilder() 061 * .appendSuper(super.equals(obj)) 062 * .append(field1, rhs.field1) 063 * .append(field2, rhs.field2) 064 * .append(field3, rhs.field3) 065 * .isEquals(); 066 * } 067 * </pre> 068 * 069 * <p> Alternatively, there is a method that uses reflection to determine 070 * the fields to test. Because these fields are usually private, the method, 071 * {@code reflectionEquals}, uses {@code AccessibleObject.setAccessible} to 072 * change the visibility of the fields. This will fail under a security 073 * manager, unless the appropriate permissions are set up correctly. It is 074 * also slower than testing explicitly. Non-primitive fields are compared using 075 * {@code equals()}.</p> 076 * 077 * <p> A typical invocation for this method would look like:</p> 078 * <pre> 079 * public boolean equals(Object obj) { 080 * return EqualsBuilder.reflectionEquals(this, obj); 081 * } 082 * </pre> 083 * 084 * <p>The {@link EqualsExclude} annotation can be used to exclude fields from being 085 * used by the {@code reflectionEquals} methods.</p> 086 * 087 * @since 1.0 088 */ 089public 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<>(); 099 100 /* 101 * NOTE: 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 hash code 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.identityHashCode() 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} object 136 * @param rhs the other object 137 * 138 * @return the pair 139 */ 140 static Pair<IDKey, IDKey> getRegisterPair(final Object lhs, final Object rhs) { 141 final IDKey left = new IDKey(lhs); 142 final IDKey right = new IDKey(rhs); 143 return Pair.of(left, right); 144 } 145 146 /** 147 * <p> 148 * Returns {@code true} 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} object to lookup in registry 155 * @param rhs the other object to lookup on registry 156 * @return boolean {@code true} if the registry contains the given object. 157 * @since 3.0 158 */ 159 static boolean isRegistered(final Object lhs, final Object rhs) { 160 final Set<Pair<IDKey, IDKey>> registry = getRegistry(); 161 final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); 162 final Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getRight(), pair.getLeft()); 163 164 return registry != null 165 && (registry.contains(pair) || registry.contains(swappedPair)); 166 } 167 168 /** 169 * <p> 170 * Registers the given object pair. 171 * Used by the reflection methods to avoid infinite loops. 172 * </p> 173 * 174 * @param lhs {@code this} object to register 175 * @param rhs the other object to register 176 */ 177 private static void register(final Object lhs, final Object rhs) { 178 Set<Pair<IDKey, IDKey>> registry = getRegistry(); 179 if (registry == null) { 180 registry = new HashSet<>(); 181 REGISTRY.set(registry); 182 } 183 final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); 184 registry.add(pair); 185 } 186 187 /** 188 * <p> 189 * Unregisters the given object pair. 190 * </p> 191 * 192 * <p> 193 * Used by the reflection methods to avoid infinite loops. 194 * 195 * @param lhs {@code this} object to unregister 196 * @param rhs the other object to unregister 197 * @since 3.0 198 */ 199 private static void unregister(final Object lhs, final Object rhs) { 200 final Set<Pair<IDKey, IDKey>> registry = getRegistry(); 201 if (registry != null) { 202 final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); 203 registry.remove(pair); 204 if (registry.isEmpty()) { 205 REGISTRY.remove(); 206 } 207 } 208 } 209 210 /** 211 * If the fields tested are equals. 212 * The default value is {@code true}. 213 */ 214 private boolean isEquals = true; 215 216 private boolean testTransients = false; 217 private boolean testRecursive = false; 218 private List<Class<?>> bypassReflectionClasses; 219 private Class<?> reflectUpToClass = null; 220 private String[] excludeFields = null; 221 222 /** 223 * <p>Constructor for EqualsBuilder.</p> 224 * 225 * <p>Starts off assuming that equals is {@code true}.</p> 226 * @see Object#equals(Object) 227 */ 228 public EqualsBuilder() { 229 // set up default classes to bypass reflection for 230 bypassReflectionClasses = new ArrayList<>(); 231 bypassReflectionClasses.add(String.class); //hashCode field being lazy but not transient 232 } 233 234 //------------------------------------------------------------------------- 235 236 /** 237 * Set whether to include transient fields when reflectively comparing objects. 238 * @param testTransients whether to test transient fields 239 * @return EqualsBuilder - used to chain calls. 240 * @since 3.6 241 */ 242 public EqualsBuilder setTestTransients(final boolean testTransients) { 243 this.testTransients = testTransients; 244 return this; 245 } 246 247 /** 248 * Set whether to test fields recursively, instead of using their equals method, when reflectively comparing objects. 249 * String objects, which cache a hash value, are automatically excluded from recursive testing. 250 * You may specify other exceptions by calling {@link #setBypassReflectionClasses(List)}. 251 * @param testRecursive whether to do a recursive test 252 * @return EqualsBuilder - used to chain calls. 253 * @see #setBypassReflectionClasses(List) 254 * @since 3.6 255 */ 256 public EqualsBuilder setTestRecursive(final boolean testRecursive) { 257 this.testRecursive = testRecursive; 258 return this; 259 } 260 261 /** 262 * <p>Set {@code Class}es whose instances should be compared by calling their {@code equals} 263 * although being in recursive mode. So the fields of theses classes will not be compared recursively by reflection.</p> 264 * 265 * <p>Here you should name classes having non-transient fields which are cache fields being set lazily.<br> 266 * Prominent example being {@link String} class with its hash code cache field. Due to the importance 267 * of the {@code String} class, it is included in the default bypasses classes. Usually, if you use 268 * your own set of classes here, remember to include {@code String} class, too.</p> 269 * @param bypassReflectionClasses classes to bypass reflection test 270 * @return EqualsBuilder - used to chain calls. 271 * @see #setTestRecursive(boolean) 272 * @since 3.8 273 */ 274 public EqualsBuilder setBypassReflectionClasses(final List<Class<?>> bypassReflectionClasses) { 275 this.bypassReflectionClasses = bypassReflectionClasses; 276 return this; 277 } 278 279 /** 280 * Set the superclass to reflect up to at reflective tests. 281 * @param reflectUpToClass the super class to reflect up to 282 * @return EqualsBuilder - used to chain calls. 283 * @since 3.6 284 */ 285 public EqualsBuilder setReflectUpToClass(final Class<?> reflectUpToClass) { 286 this.reflectUpToClass = reflectUpToClass; 287 return this; 288 } 289 290 /** 291 * Set field names to be excluded by reflection tests. 292 * @param excludeFields the fields to exclude 293 * @return EqualsBuilder - used to chain calls. 294 * @since 3.6 295 */ 296 public EqualsBuilder setExcludeFields(final String... excludeFields) { 297 this.excludeFields = excludeFields; 298 return this; 299 } 300 301 302 /** 303 * <p>This method uses reflection to determine if the two {@code Object}s 304 * are equal.</p> 305 * 306 * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private 307 * fields. This means that it will throw a security exception if run under 308 * a security manager, if the permissions are not set up correctly. It is also 309 * not as efficient as testing explicitly. Non-primitive fields are compared using 310 * {@code equals()}.</p> 311 * 312 * <p>Transient members will be not be tested, as they are likely derived 313 * fields, and not part of the value of the Object.</p> 314 * 315 * <p>Static fields will not be tested. Superclass fields will be included.</p> 316 * 317 * @param lhs {@code this} object 318 * @param rhs the other object 319 * @param excludeFields Collection of String field names to exclude from testing 320 * @return {@code true} if the two Objects have tested equals. 321 * 322 * @see EqualsExclude 323 */ 324 public static boolean reflectionEquals(final Object lhs, final Object rhs, final Collection<String> excludeFields) { 325 return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); 326 } 327 328 /** 329 * <p>This method uses reflection to determine if the two {@code Object}s 330 * are equal.</p> 331 * 332 * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private 333 * fields. This means that it will throw a security exception if run under 334 * a security manager, if the permissions are not set up correctly. It is also 335 * not as efficient as testing explicitly. Non-primitive fields are compared using 336 * {@code equals()}.</p> 337 * 338 * <p>Transient members will be not be tested, as they are likely derived 339 * fields, and not part of the value of the Object.</p> 340 * 341 * <p>Static fields will not be tested. Superclass fields will be included.</p> 342 * 343 * @param lhs {@code this} object 344 * @param rhs the other object 345 * @param excludeFields array of field names to exclude from testing 346 * @return {@code true} if the two Objects have tested equals. 347 * 348 * @see EqualsExclude 349 */ 350 public static boolean reflectionEquals(final Object lhs, final Object rhs, final String... excludeFields) { 351 return reflectionEquals(lhs, rhs, false, null, excludeFields); 352 } 353 354 /** 355 * <p>This method uses reflection to determine if the two {@code Object}s 356 * are equal.</p> 357 * 358 * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private 359 * fields. This means that it will throw a security exception if run under 360 * a security manager, if the permissions are not set up correctly. It is also 361 * not as efficient as testing explicitly. Non-primitive fields are compared using 362 * {@code equals()}.</p> 363 * 364 * <p>If the TestTransients parameter is set to {@code true}, transient 365 * members will be tested, otherwise they are ignored, as they are likely 366 * derived fields, and not part of the value of the {@code Object}.</p> 367 * 368 * <p>Static fields will not be tested. Superclass fields will be included.</p> 369 * 370 * @param lhs {@code this} object 371 * @param rhs the other object 372 * @param testTransients whether to include transient fields 373 * @return {@code true} if the two Objects have tested equals. 374 * 375 * @see EqualsExclude 376 */ 377 public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients) { 378 return reflectionEquals(lhs, rhs, testTransients, null); 379 } 380 381 /** 382 * <p>This method uses reflection to determine if the two {@code Object}s 383 * are equal.</p> 384 * 385 * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private 386 * fields. This means that it will throw a security exception if run under 387 * a security manager, if the permissions are not set up correctly. It is also 388 * not as efficient as testing explicitly. Non-primitive fields are compared using 389 * {@code equals()}.</p> 390 * 391 * <p>If the testTransients parameter is set to {@code true}, transient 392 * members will be tested, otherwise they are ignored, as they are likely 393 * derived fields, and not part of the value of the {@code Object}.</p> 394 * 395 * <p>Static fields will not be included. Superclass fields will be appended 396 * up to and including the specified superclass. A null superclass is treated 397 * as java.lang.Object.</p> 398 * 399 * @param lhs {@code this} object 400 * @param rhs the other object 401 * @param testTransients whether to include transient fields 402 * @param reflectUpToClass the superclass to reflect up to (inclusive), 403 * may be {@code null} 404 * @param excludeFields array of field names to exclude from testing 405 * @return {@code true} if the two Objects have tested equals. 406 * 407 * @see EqualsExclude 408 * @since 2.0 409 */ 410 public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass, 411 final String... excludeFields) { 412 return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, false, excludeFields); 413 } 414 415 /** 416 * <p>This method uses reflection to determine if the two {@code Object}s 417 * are equal.</p> 418 * 419 * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private 420 * fields. This means that it will throw a security exception if run under 421 * a security manager, if the permissions are not set up correctly. It is also 422 * not as efficient as testing explicitly. Non-primitive fields are compared using 423 * {@code equals()}.</p> 424 * 425 * <p>If the testTransients parameter is set to {@code true}, transient 426 * members will be tested, otherwise they are ignored, as they are likely 427 * derived fields, and not part of the value of the {@code Object}.</p> 428 * 429 * <p>Static fields will not be included. Superclass fields will be appended 430 * up to and including the specified superclass. A null superclass is treated 431 * as java.lang.Object.</p> 432 * 433 * <p>If the testRecursive parameter is set to {@code true}, non primitive 434 * (and non primitive wrapper) field types will be compared by 435 * {@code EqualsBuilder} recursively instead of invoking their 436 * {@code equals()} method. Leading to a deep reflection equals test. 437 * 438 * @param lhs {@code this} object 439 * @param rhs the other object 440 * @param testTransients whether to include transient fields 441 * @param reflectUpToClass the superclass to reflect up to (inclusive), 442 * may be {@code null} 443 * @param testRecursive whether to call reflection equals on non primitive 444 * fields recursively. 445 * @param excludeFields array of field names to exclude from testing 446 * @return {@code true} if the two Objects have tested equals. 447 * 448 * @see EqualsExclude 449 * @since 3.6 450 */ 451 public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass, 452 final boolean testRecursive, final String... excludeFields) { 453 if (lhs == rhs) { 454 return true; 455 } 456 if (lhs == null || rhs == null) { 457 return false; 458 } 459 return new EqualsBuilder() 460 .setExcludeFields(excludeFields) 461 .setReflectUpToClass(reflectUpToClass) 462 .setTestTransients(testTransients) 463 .setTestRecursive(testRecursive) 464 .reflectionAppend(lhs, rhs) 465 .isEquals(); 466 } 467 468 /** 469 * <p>Tests if two {@code objects} by using reflection.</p> 470 * 471 * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private 472 * fields. This means that it will throw a security exception if run under 473 * a security manager, if the permissions are not set up correctly. It is also 474 * not as efficient as testing explicitly. Non-primitive fields are compared using 475 * {@code equals()}.</p> 476 * 477 * <p>If the testTransients field is set to {@code true}, transient 478 * members will be tested, otherwise they are ignored, as they are likely 479 * derived fields, and not part of the value of the {@code Object}.</p> 480 * 481 * <p>Static fields will not be included. Superclass fields will be appended 482 * up to and including the specified superclass in field {@code reflectUpToClass}. 483 * A null superclass is treated as java.lang.Object.</p> 484 * 485 * <p>Field names listed in field {@code excludeFields} will be ignored.</p> 486 * 487 * <p>If either class of the compared objects is contained in 488 * {@code bypassReflectionClasses}, both objects are compared by calling 489 * the equals method of the left hand object with the right hand object as an argument.</p> 490 * 491 * @param lhs the left hand object 492 * @param rhs the left hand object 493 * @return EqualsBuilder - used to chain calls. 494 */ 495 public EqualsBuilder reflectionAppend(final Object lhs, final Object rhs) { 496 if (!isEquals) { 497 return this; 498 } 499 if (lhs == rhs) { 500 return this; 501 } 502 if (lhs == null || rhs == null) { 503 isEquals = false; 504 return this; 505 } 506 507 // Find the leaf class since there may be transients in the leaf 508 // class or in classes between the leaf and root. 509 // If we are not testing transients or a subclass has no ivars, 510 // then a subclass can test equals to a superclass. 511 final Class<?> lhsClass = lhs.getClass(); 512 final Class<?> rhsClass = rhs.getClass(); 513 Class<?> testClass; 514 if (lhsClass.isInstance(rhs)) { 515 testClass = lhsClass; 516 if (!rhsClass.isInstance(lhs)) { 517 // rhsClass is a subclass of lhsClass 518 testClass = rhsClass; 519 } 520 } else if (rhsClass.isInstance(lhs)) { 521 testClass = rhsClass; 522 if (!lhsClass.isInstance(rhs)) { 523 // lhsClass is a subclass of rhsClass 524 testClass = lhsClass; 525 } 526 } else { 527 // The two classes are not related. 528 isEquals = false; 529 return this; 530 } 531 532 try { 533 if (testClass.isArray()) { 534 append(lhs, rhs); 535 } else { 536 //If either class is being excluded, call normal object equals method on lhsClass. 537 if (bypassReflectionClasses != null 538 && (bypassReflectionClasses.contains(lhsClass) || bypassReflectionClasses.contains(rhsClass))) { 539 isEquals = lhs.equals(rhs); 540 } else { 541 reflectionAppend(lhs, rhs, testClass); 542 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) { 543 testClass = testClass.getSuperclass(); 544 reflectionAppend(lhs, rhs, testClass); 545 } 546 } 547 } 548 } catch (final IllegalArgumentException e) { 549 // In this case, we tried to test a subclass vs. a superclass and 550 // the subclass has ivars or the ivars are transient and 551 // we are testing transients. 552 // If a subclass has ivars that we are trying to test them, we get an 553 // exception and we know that the objects are not equal. 554 isEquals = false; 555 return this; 556 } 557 return this; 558 } 559 560 /** 561 * <p>Appends the fields and values defined by the given object of the 562 * given Class.</p> 563 * 564 * @param lhs the left hand object 565 * @param rhs the right hand object 566 * @param clazz the class to append details of 567 */ 568 private void reflectionAppend( 569 final Object lhs, 570 final Object rhs, 571 final Class<?> clazz) { 572 573 if (isRegistered(lhs, rhs)) { 574 return; 575 } 576 577 try { 578 register(lhs, rhs); 579 final Field[] fields = clazz.getDeclaredFields(); 580 AccessibleObject.setAccessible(fields, true); 581 for (int i = 0; i < fields.length && isEquals; i++) { 582 final Field f = fields[i]; 583 if (!ArrayUtils.contains(excludeFields, f.getName()) 584 && !f.getName().contains("$") 585 && (testTransients || !Modifier.isTransient(f.getModifiers())) 586 && !Modifier.isStatic(f.getModifiers()) 587 && !f.isAnnotationPresent(EqualsExclude.class)) { 588 try { 589 append(f.get(lhs), f.get(rhs)); 590 } catch (final IllegalAccessException e) { 591 //this can't happen. Would get a Security exception instead 592 //throw a runtime exception in case the impossible happens. 593 throw new InternalError("Unexpected IllegalAccessException"); 594 } 595 } 596 } 597 } finally { 598 unregister(lhs, rhs); 599 } 600 } 601 602 //------------------------------------------------------------------------- 603 604 /** 605 * <p>Adds the result of {@code super.equals()} to this builder.</p> 606 * 607 * @param superEquals the result of calling {@code super.equals()} 608 * @return EqualsBuilder - used to chain calls. 609 * @since 2.0 610 */ 611 public EqualsBuilder appendSuper(final boolean superEquals) { 612 if (!isEquals) { 613 return this; 614 } 615 isEquals = superEquals; 616 return this; 617 } 618 619 //------------------------------------------------------------------------- 620 621 /** 622 * <p>Test if two {@code Object}s are equal using either 623 * #{@link #reflectionAppend(Object, Object)}, if object are non 624 * primitives (or wrapper of primitives) or if field {@code testRecursive} 625 * is set to {@code false}. Otherwise, using their 626 * {@code equals} method.</p> 627 * 628 * @param lhs the left hand object 629 * @param rhs the right hand object 630 * @return EqualsBuilder - used to chain calls. 631 */ 632 public EqualsBuilder append(final Object lhs, final Object rhs) { 633 if (!isEquals) { 634 return this; 635 } 636 if (lhs == rhs) { 637 return this; 638 } 639 if (lhs == null || rhs == null) { 640 this.setEquals(false); 641 return this; 642 } 643 final Class<?> lhsClass = lhs.getClass(); 644 if (lhsClass.isArray()) { 645 // factor out array case in order to keep method small enough 646 // to be inlined 647 appendArray(lhs, rhs); 648 } else { 649 // The simple case, not an array, just test the element 650 if (testRecursive && !ClassUtils.isPrimitiveOrWrapper(lhsClass)) { 651 reflectionAppend(lhs, rhs); 652 } else { 653 isEquals = lhs.equals(rhs); 654 } 655 } 656 return this; 657 } 658 659 /** 660 * <p>Test if an {@code Object} is equal to an array.</p> 661 * 662 * @param lhs the left hand object, an array 663 * @param rhs the right hand object 664 */ 665 private void appendArray(final Object lhs, final Object rhs) { 666 // First we compare different dimensions, for example: a boolean[][] to a boolean[] 667 // then we 'Switch' on type of array, to dispatch to the correct handler 668 // This handles multi dimensional arrays of the same depth 669 if (lhs.getClass() != rhs.getClass()) { 670 this.setEquals(false); 671 } else if (lhs instanceof long[]) { 672 append((long[]) lhs, (long[]) rhs); 673 } else if (lhs instanceof int[]) { 674 append((int[]) lhs, (int[]) rhs); 675 } else if (lhs instanceof short[]) { 676 append((short[]) lhs, (short[]) rhs); 677 } else if (lhs instanceof char[]) { 678 append((char[]) lhs, (char[]) rhs); 679 } else if (lhs instanceof byte[]) { 680 append((byte[]) lhs, (byte[]) rhs); 681 } else if (lhs instanceof double[]) { 682 append((double[]) lhs, (double[]) rhs); 683 } else if (lhs instanceof float[]) { 684 append((float[]) lhs, (float[]) rhs); 685 } else if (lhs instanceof boolean[]) { 686 append((boolean[]) lhs, (boolean[]) rhs); 687 } else { 688 // Not an array of primitives 689 append((Object[]) lhs, (Object[]) rhs); 690 } 691 } 692 693 /** 694 * <p> 695 * Test if two {@code long} s are equal. 696 * </p> 697 * 698 * @param lhs 699 * the left hand {@code long} 700 * @param rhs 701 * the right hand {@code long} 702 * @return EqualsBuilder - used to chain calls. 703 */ 704 public EqualsBuilder append(final long lhs, final long rhs) { 705 if (!isEquals) { 706 return this; 707 } 708 isEquals = lhs == rhs; 709 return this; 710 } 711 712 /** 713 * <p>Test if two {@code int}s are equal.</p> 714 * 715 * @param lhs the left hand {@code int} 716 * @param rhs the right hand {@code int} 717 * @return EqualsBuilder - used to chain calls. 718 */ 719 public EqualsBuilder append(final int lhs, final int rhs) { 720 if (!isEquals) { 721 return this; 722 } 723 isEquals = lhs == rhs; 724 return this; 725 } 726 727 /** 728 * <p>Test if two {@code short}s are equal.</p> 729 * 730 * @param lhs the left hand {@code short} 731 * @param rhs the right hand {@code short} 732 * @return EqualsBuilder - used to chain calls. 733 */ 734 public EqualsBuilder append(final short lhs, final short rhs) { 735 if (!isEquals) { 736 return this; 737 } 738 isEquals = lhs == rhs; 739 return this; 740 } 741 742 /** 743 * <p>Test if two {@code char}s are equal.</p> 744 * 745 * @param lhs the left hand {@code char} 746 * @param rhs the right hand {@code char} 747 * @return EqualsBuilder - used to chain calls. 748 */ 749 public EqualsBuilder append(final char lhs, final char rhs) { 750 if (!isEquals) { 751 return this; 752 } 753 isEquals = lhs == rhs; 754 return this; 755 } 756 757 /** 758 * <p>Test if two {@code byte}s are equal.</p> 759 * 760 * @param lhs the left hand {@code byte} 761 * @param rhs the right hand {@code byte} 762 * @return EqualsBuilder - used to chain calls. 763 */ 764 public EqualsBuilder append(final byte lhs, final byte rhs) { 765 if (!isEquals) { 766 return this; 767 } 768 isEquals = lhs == rhs; 769 return this; 770 } 771 772 /** 773 * <p>Test if two {@code double}s are equal by testing that the 774 * pattern of bits returned by {@code doubleToLong} are equal.</p> 775 * 776 * <p>This handles NaNs, Infinities, and {@code -0.0}.</p> 777 * 778 * <p>It is compatible with the hash code generated by 779 * {@code HashCodeBuilder}.</p> 780 * 781 * @param lhs the left hand {@code double} 782 * @param rhs the right hand {@code double} 783 * @return EqualsBuilder - used to chain calls. 784 */ 785 public EqualsBuilder append(final double lhs, final double rhs) { 786 if (!isEquals) { 787 return this; 788 } 789 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs)); 790 } 791 792 /** 793 * <p>Test if two {@code float}s are equal by testing that the 794 * pattern of bits returned by doubleToLong are equal.</p> 795 * 796 * <p>This handles NaNs, Infinities, and {@code -0.0}.</p> 797 * 798 * <p>It is compatible with the hash code generated by 799 * {@code HashCodeBuilder}.</p> 800 * 801 * @param lhs the left hand {@code float} 802 * @param rhs the right hand {@code float} 803 * @return EqualsBuilder - used to chain calls. 804 */ 805 public EqualsBuilder append(final float lhs, final float rhs) { 806 if (!isEquals) { 807 return this; 808 } 809 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs)); 810 } 811 812 /** 813 * <p>Test if two {@code booleans}s are equal.</p> 814 * 815 * @param lhs the left hand {@code boolean} 816 * @param rhs the right hand {@code boolean} 817 * @return EqualsBuilder - used to chain calls. 818 */ 819 public EqualsBuilder append(final boolean lhs, final boolean rhs) { 820 if (!isEquals) { 821 return this; 822 } 823 isEquals = lhs == rhs; 824 return this; 825 } 826 827 /** 828 * <p>Performs a deep comparison of two {@code Object} arrays.</p> 829 * 830 * <p>This also will be called for the top level of 831 * multi-dimensional, ragged, and multi-typed arrays.</p> 832 * 833 * <p>Note that this method does not compare the type of the arrays; it only 834 * compares the contents.</p> 835 * 836 * @param lhs the left hand {@code Object[]} 837 * @param rhs the right hand {@code Object[]} 838 * @return EqualsBuilder - used to chain calls. 839 */ 840 public EqualsBuilder append(final Object[] lhs, final Object[] rhs) { 841 if (!isEquals) { 842 return this; 843 } 844 if (lhs == rhs) { 845 return this; 846 } 847 if (lhs == null || rhs == null) { 848 this.setEquals(false); 849 return this; 850 } 851 if (lhs.length != rhs.length) { 852 this.setEquals(false); 853 return this; 854 } 855 for (int i = 0; i < lhs.length && isEquals; ++i) { 856 append(lhs[i], rhs[i]); 857 } 858 return this; 859 } 860 861 /** 862 * <p>Deep comparison of array of {@code long}. Length and all 863 * values are compared.</p> 864 * 865 * <p>The method {@link #append(long, long)} is used.</p> 866 * 867 * @param lhs the left hand {@code long[]} 868 * @param rhs the right hand {@code long[]} 869 * @return EqualsBuilder - used to chain calls. 870 */ 871 public EqualsBuilder append(final long[] lhs, final long[] rhs) { 872 if (!isEquals) { 873 return this; 874 } 875 if (lhs == rhs) { 876 return this; 877 } 878 if (lhs == null || rhs == null) { 879 this.setEquals(false); 880 return this; 881 } 882 if (lhs.length != rhs.length) { 883 this.setEquals(false); 884 return this; 885 } 886 for (int i = 0; i < lhs.length && isEquals; ++i) { 887 append(lhs[i], rhs[i]); 888 } 889 return this; 890 } 891 892 /** 893 * <p>Deep comparison of array of {@code int}. Length and all 894 * values are compared.</p> 895 * 896 * <p>The method {@link #append(int, int)} is used.</p> 897 * 898 * @param lhs the left hand {@code int[]} 899 * @param rhs the right hand {@code int[]} 900 * @return EqualsBuilder - used to chain calls. 901 */ 902 public EqualsBuilder append(final int[] lhs, final int[] rhs) { 903 if (!isEquals) { 904 return this; 905 } 906 if (lhs == rhs) { 907 return this; 908 } 909 if (lhs == null || rhs == null) { 910 this.setEquals(false); 911 return this; 912 } 913 if (lhs.length != rhs.length) { 914 this.setEquals(false); 915 return this; 916 } 917 for (int i = 0; i < lhs.length && isEquals; ++i) { 918 append(lhs[i], rhs[i]); 919 } 920 return this; 921 } 922 923 /** 924 * <p>Deep comparison of array of {@code short}. Length and all 925 * values are compared.</p> 926 * 927 * <p>The method {@link #append(short, short)} is used.</p> 928 * 929 * @param lhs the left hand {@code short[]} 930 * @param rhs the right hand {@code short[]} 931 * @return EqualsBuilder - used to chain calls. 932 */ 933 public EqualsBuilder append(final short[] lhs, final short[] rhs) { 934 if (!isEquals) { 935 return this; 936 } 937 if (lhs == rhs) { 938 return this; 939 } 940 if (lhs == null || rhs == null) { 941 this.setEquals(false); 942 return this; 943 } 944 if (lhs.length != rhs.length) { 945 this.setEquals(false); 946 return this; 947 } 948 for (int i = 0; i < lhs.length && isEquals; ++i) { 949 append(lhs[i], rhs[i]); 950 } 951 return this; 952 } 953 954 /** 955 * <p>Deep comparison of array of {@code char}. Length and all 956 * values are compared.</p> 957 * 958 * <p>The method {@link #append(char, char)} is used.</p> 959 * 960 * @param lhs the left hand {@code char[]} 961 * @param rhs the right hand {@code char[]} 962 * @return EqualsBuilder - used to chain calls. 963 */ 964 public EqualsBuilder append(final char[] lhs, final char[] rhs) { 965 if (!isEquals) { 966 return this; 967 } 968 if (lhs == rhs) { 969 return this; 970 } 971 if (lhs == null || rhs == null) { 972 this.setEquals(false); 973 return this; 974 } 975 if (lhs.length != rhs.length) { 976 this.setEquals(false); 977 return this; 978 } 979 for (int i = 0; i < lhs.length && isEquals; ++i) { 980 append(lhs[i], rhs[i]); 981 } 982 return this; 983 } 984 985 /** 986 * <p>Deep comparison of array of {@code byte}. Length and all 987 * values are compared.</p> 988 * 989 * <p>The method {@link #append(byte, byte)} is used.</p> 990 * 991 * @param lhs the left hand {@code byte[]} 992 * @param rhs the right hand {@code byte[]} 993 * @return EqualsBuilder - used to chain calls. 994 */ 995 public EqualsBuilder append(final byte[] lhs, final byte[] rhs) { 996 if (!isEquals) { 997 return this; 998 } 999 if (lhs == rhs) { 1000 return this; 1001 } 1002 if (lhs == null || rhs == null) { 1003 this.setEquals(false); 1004 return this; 1005 } 1006 if (lhs.length != rhs.length) { 1007 this.setEquals(false); 1008 return this; 1009 } 1010 for (int i = 0; i < lhs.length && isEquals; ++i) { 1011 append(lhs[i], rhs[i]); 1012 } 1013 return this; 1014 } 1015 1016 /** 1017 * <p>Deep comparison of array of {@code double}. Length and all 1018 * values are compared.</p> 1019 * 1020 * <p>The method {@link #append(double, double)} is used.</p> 1021 * 1022 * @param lhs the left hand {@code double[]} 1023 * @param rhs the right hand {@code double[]} 1024 * @return EqualsBuilder - used to chain calls. 1025 */ 1026 public EqualsBuilder append(final double[] lhs, final double[] rhs) { 1027 if (!isEquals) { 1028 return this; 1029 } 1030 if (lhs == rhs) { 1031 return this; 1032 } 1033 if (lhs == null || rhs == null) { 1034 this.setEquals(false); 1035 return this; 1036 } 1037 if (lhs.length != rhs.length) { 1038 this.setEquals(false); 1039 return this; 1040 } 1041 for (int i = 0; i < lhs.length && isEquals; ++i) { 1042 append(lhs[i], rhs[i]); 1043 } 1044 return this; 1045 } 1046 1047 /** 1048 * <p>Deep comparison of array of {@code float}. Length and all 1049 * values are compared.</p> 1050 * 1051 * <p>The method {@link #append(float, float)} is used.</p> 1052 * 1053 * @param lhs the left hand {@code float[]} 1054 * @param rhs the right hand {@code float[]} 1055 * @return EqualsBuilder - used to chain calls. 1056 */ 1057 public EqualsBuilder append(final float[] lhs, final float[] rhs) { 1058 if (!isEquals) { 1059 return this; 1060 } 1061 if (lhs == rhs) { 1062 return this; 1063 } 1064 if (lhs == null || rhs == null) { 1065 this.setEquals(false); 1066 return this; 1067 } 1068 if (lhs.length != rhs.length) { 1069 this.setEquals(false); 1070 return this; 1071 } 1072 for (int i = 0; i < lhs.length && isEquals; ++i) { 1073 append(lhs[i], rhs[i]); 1074 } 1075 return this; 1076 } 1077 1078 /** 1079 * <p>Deep comparison of array of {@code boolean}. Length and all 1080 * values are compared.</p> 1081 * 1082 * <p>The method {@link #append(boolean, boolean)} is used.</p> 1083 * 1084 * @param lhs the left hand {@code boolean[]} 1085 * @param rhs the right hand {@code boolean[]} 1086 * @return EqualsBuilder - used to chain calls. 1087 */ 1088 public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) { 1089 if (!isEquals) { 1090 return this; 1091 } 1092 if (lhs == rhs) { 1093 return this; 1094 } 1095 if (lhs == null || rhs == null) { 1096 this.setEquals(false); 1097 return this; 1098 } 1099 if (lhs.length != rhs.length) { 1100 this.setEquals(false); 1101 return this; 1102 } 1103 for (int i = 0; i < lhs.length && isEquals; ++i) { 1104 append(lhs[i], rhs[i]); 1105 } 1106 return this; 1107 } 1108 1109 /** 1110 * <p>Returns {@code true} if the fields that have been checked 1111 * are all equal.</p> 1112 * 1113 * @return boolean 1114 */ 1115 public boolean isEquals() { 1116 return this.isEquals; 1117 } 1118 1119 /** 1120 * <p>Returns {@code true} if the fields that have been checked 1121 * are all equal.</p> 1122 * 1123 * @return {@code true} if all of the fields that have been checked 1124 * are equal, {@code false} otherwise. 1125 * 1126 * @since 3.0 1127 */ 1128 @Override 1129 public Boolean build() { 1130 return Boolean.valueOf(isEquals()); 1131 } 1132 1133 /** 1134 * Sets the {@code isEquals} value. 1135 * 1136 * @param isEquals The value to set. 1137 * @since 2.1 1138 */ 1139 protected void setEquals(final boolean isEquals) { 1140 this.isEquals = isEquals; 1141 } 1142 1143 /** 1144 * Reset the EqualsBuilder so you can use the same object again 1145 * @since 2.5 1146 */ 1147 public void reset() { 1148 this.isEquals = true; 1149 } 1150}