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