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