001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.lang.builder; 018 019 import java.lang.reflect.AccessibleObject; 020 import java.lang.reflect.Field; 021 import java.lang.reflect.Modifier; 022 import java.util.Arrays; 023 import java.util.Collection; 024 import java.util.Collections; 025 import java.util.List; 026 027 /** 028 * <p>Assists in implementing {@link Object#equals(Object)} methods.</p> 029 * 030 * <p> This class provides methods to build a good equals method for any 031 * class. It follows rules laid out in 032 * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a> 033 * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>, 034 * <code>floats</code>, and arrays can be tricky. Also, making sure that 035 * <code>equals()</code> and <code>hashCode()</code> are consistent can be 036 * difficult.</p> 037 * 038 * <p>Two Objects that compare as equals must generate the same hash code, 039 * but two Objects with the same hash code do not have to be equal.</p> 040 * 041 * <p>All relevant fields should be included in the calculation of equals. 042 * Derived fields may be ignored. In particular, any field used in 043 * generating a hash code must be used in the equals method, and vice 044 * versa.</p> 045 * 046 * <p>Typical use for the code is as follows:</p> 047 * <pre> 048 * public boolean equals(Object obj) { 049 * if (obj == null) { return false; } 050 * if (obj == this) { return true; } 051 * if (obj.getClass() != getClass()) { 052 * return false; 053 * } 054 * MyClass rhs = (MyClass) obj; 055 * return new EqualsBuilder() 056 * .appendSuper(super.equals(obj)) 057 * .append(field1, rhs.field1) 058 * .append(field2, rhs.field2) 059 * .append(field3, rhs.field3) 060 * .isEquals(); 061 * } 062 * </pre> 063 * 064 * <p> Alternatively, there is a method that uses reflection to determine 065 * the fields to test. Because these fields are usually private, the method, 066 * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to 067 * change the visibility of the fields. This will fail under a security 068 * manager, unless the appropriate permissions are set up correctly. It is 069 * also slower than testing explicitly.</p> 070 * 071 * <p> A typical invocation for this method would look like:</p> 072 * <pre> 073 * public boolean equals(Object obj) { 074 * return EqualsBuilder.reflectionEquals(this, obj); 075 * } 076 * </pre> 077 * 078 * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a> 079 * @author Stephen Colebourne 080 * @author Gary Gregory 081 * @author Pete Gieser 082 * @author Arun Mammen Thomas 083 * @since 1.0 084 * @version $Id: EqualsBuilder.java 611543 2008-01-13 07:00:22Z bayard $ 085 */ 086 public class EqualsBuilder { 087 088 /** 089 * If the fields tested are equals. 090 * The default value is <code>true</code>. 091 */ 092 private boolean isEquals = true; 093 094 /** 095 * <p>Constructor for EqualsBuilder.</p> 096 * 097 * <p>Starts off assuming that equals is <code>true</code>.</p> 098 * @see Object#equals(Object) 099 */ 100 public EqualsBuilder() { 101 // do nothing for now. 102 } 103 104 //------------------------------------------------------------------------- 105 106 /** 107 * <p>This method uses reflection to determine if the two <code>Object</code>s 108 * are equal.</p> 109 * 110 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 111 * fields. This means that it will throw a security exception if run under 112 * a security manager, if the permissions are not set up correctly. It is also 113 * not as efficient as testing explicitly.</p> 114 * 115 * <p>Transient members will be not be tested, as they are likely derived 116 * fields, and not part of the value of the Object.</p> 117 * 118 * <p>Static fields will not be tested. Superclass fields will be included.</p> 119 * 120 * @param lhs <code>this</code> object 121 * @param rhs the other object 122 * @return <code>true</code> if the two Objects have tested equals. 123 */ 124 public static boolean reflectionEquals(Object lhs, Object rhs) { 125 return reflectionEquals(lhs, rhs, false, null, null); 126 } 127 128 /** 129 * <p>This method uses reflection to determine if the two <code>Object</code>s 130 * are equal.</p> 131 * 132 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 133 * fields. This means that it will throw a security exception if run under 134 * a security manager, if the permissions are not set up correctly. It is also 135 * not as efficient as testing explicitly.</p> 136 * 137 * <p>Transient members will be not be tested, as they are likely derived 138 * fields, and not part of the value of the Object.</p> 139 * 140 * <p>Static fields will not be tested. Superclass fields will be included.</p> 141 * 142 * @param lhs <code>this</code> object 143 * @param rhs the other object 144 * @param excludeFields Collection of String field names to exclude from testing 145 * @return <code>true</code> if the two Objects have tested equals. 146 */ 147 public static boolean reflectionEquals(Object lhs, Object rhs, Collection /*String*/ excludeFields) { 148 return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); 149 } 150 151 /** 152 * <p>This method uses reflection to determine if the two <code>Object</code>s 153 * are equal.</p> 154 * 155 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 156 * fields. This means that it will throw a security exception if run under 157 * a security manager, if the permissions are not set up correctly. It is also 158 * not as efficient as testing explicitly.</p> 159 * 160 * <p>Transient members will be not be tested, as they are likely derived 161 * fields, and not part of the value of the Object.</p> 162 * 163 * <p>Static fields will not be tested. Superclass fields will be included.</p> 164 * 165 * @param lhs <code>this</code> object 166 * @param rhs the other object 167 * @param excludeFields array of field names to exclude from testing 168 * @return <code>true</code> if the two Objects have tested equals. 169 */ 170 public static boolean reflectionEquals(Object lhs, Object rhs, String[] excludeFields) { 171 return reflectionEquals(lhs, rhs, false, null, excludeFields); 172 } 173 174 /** 175 * <p>This method uses reflection to determine if the two <code>Object</code>s 176 * are equal.</p> 177 * 178 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 179 * fields. This means that it will throw a security exception if run under 180 * a security manager, if the permissions are not set up correctly. It is also 181 * not as efficient as testing explicitly.</p> 182 * 183 * <p>If the TestTransients parameter is set to <code>true</code>, transient 184 * members will be tested, otherwise they are ignored, as they are likely 185 * derived fields, and not part of the value of the <code>Object</code>.</p> 186 * 187 * <p>Static fields will not be tested. Superclass fields will be included.</p> 188 * 189 * @param lhs <code>this</code> object 190 * @param rhs the other object 191 * @param testTransients whether to include transient fields 192 * @return <code>true</code> if the two Objects have tested equals. 193 */ 194 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) { 195 return reflectionEquals(lhs, rhs, testTransients, null, null); 196 } 197 198 /** 199 * <p>This method uses reflection to determine if the two <code>Object</code>s 200 * are equal.</p> 201 * 202 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 203 * fields. This means that it will throw a security exception if run under 204 * a security manager, if the permissions are not set up correctly. It is also 205 * not as efficient as testing explicitly.</p> 206 * 207 * <p>If the testTransients parameter is set to <code>true</code>, transient 208 * members will be tested, otherwise they are ignored, as they are likely 209 * derived fields, and not part of the value of the <code>Object</code>.</p> 210 * 211 * <p>Static fields will not be included. Superclass fields will be appended 212 * up to and including the specified superclass. A null superclass is treated 213 * as java.lang.Object.</p> 214 * 215 * @param lhs <code>this</code> object 216 * @param rhs the other object 217 * @param testTransients whether to include transient fields 218 * @param reflectUpToClass the superclass to reflect up to (inclusive), 219 * may be <code>null</code> 220 * @return <code>true</code> if the two Objects have tested equals. 221 * @since 2.0 222 */ 223 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass) { 224 return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, null); 225 } 226 227 /** 228 * <p>This method uses reflection to determine if the two <code>Object</code>s 229 * are equal.</p> 230 * 231 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private 232 * fields. This means that it will throw a security exception if run under 233 * a security manager, if the permissions are not set up correctly. It is also 234 * not as efficient as testing explicitly.</p> 235 * 236 * <p>If the testTransients parameter is set to <code>true</code>, transient 237 * members will be tested, otherwise they are ignored, as they are likely 238 * derived fields, and not part of the value of the <code>Object</code>.</p> 239 * 240 * <p>Static fields will not be included. Superclass fields will be appended 241 * up to and including the specified superclass. A null superclass is treated 242 * as java.lang.Object.</p> 243 * 244 * @param lhs <code>this</code> object 245 * @param rhs the other object 246 * @param testTransients whether to include transient fields 247 * @param reflectUpToClass the superclass to reflect up to (inclusive), 248 * may be <code>null</code> 249 * @param excludeFields array of field names to exclude from testing 250 * @return <code>true</code> if the two Objects have tested equals. 251 * @since 2.0 252 */ 253 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass, 254 String[] excludeFields) { 255 if (lhs == rhs) { 256 return true; 257 } 258 if (lhs == null || rhs == null) { 259 return false; 260 } 261 // Find the leaf class since there may be transients in the leaf 262 // class or in classes between the leaf and root. 263 // If we are not testing transients or a subclass has no ivars, 264 // then a subclass can test equals to a superclass. 265 Class lhsClass = lhs.getClass(); 266 Class rhsClass = rhs.getClass(); 267 Class testClass; 268 if (lhsClass.isInstance(rhs)) { 269 testClass = lhsClass; 270 if (!rhsClass.isInstance(lhs)) { 271 // rhsClass is a subclass of lhsClass 272 testClass = rhsClass; 273 } 274 } else if (rhsClass.isInstance(lhs)) { 275 testClass = rhsClass; 276 if (!lhsClass.isInstance(rhs)) { 277 // lhsClass is a subclass of rhsClass 278 testClass = lhsClass; 279 } 280 } else { 281 // The two classes are not related. 282 return false; 283 } 284 EqualsBuilder equalsBuilder = new EqualsBuilder(); 285 try { 286 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields); 287 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) { 288 testClass = testClass.getSuperclass(); 289 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields); 290 } 291 } catch (IllegalArgumentException e) { 292 // In this case, we tried to test a subclass vs. a superclass and 293 // the subclass has ivars or the ivars are transient and 294 // we are testing transients. 295 // If a subclass has ivars that we are trying to test them, we get an 296 // exception and we know that the objects are not equal. 297 return false; 298 } 299 return equalsBuilder.isEquals(); 300 } 301 302 /** 303 * <p>Appends the fields and values defined by the given object of the 304 * given Class.</p> 305 * 306 * @param lhs the left hand object 307 * @param rhs the right hand object 308 * @param clazz the class to append details of 309 * @param builder the builder to append to 310 * @param useTransients whether to test transient fields 311 * @param excludeFields array of field names to exclude from testing 312 */ 313 private static void reflectionAppend( 314 Object lhs, 315 Object rhs, 316 Class clazz, 317 EqualsBuilder builder, 318 boolean useTransients, 319 String[] excludeFields) { 320 Field[] fields = clazz.getDeclaredFields(); 321 List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) : Collections.EMPTY_LIST; 322 AccessibleObject.setAccessible(fields, true); 323 for (int i = 0; i < fields.length && builder.isEquals; i++) { 324 Field f = fields[i]; 325 if (!excludedFieldList.contains(f.getName()) 326 && (f.getName().indexOf('$') == -1) 327 && (useTransients || !Modifier.isTransient(f.getModifiers())) 328 && (!Modifier.isStatic(f.getModifiers()))) { 329 try { 330 builder.append(f.get(lhs), f.get(rhs)); 331 } catch (IllegalAccessException e) { 332 //this can't happen. Would get a Security exception instead 333 //throw a runtime exception in case the impossible happens. 334 throw new InternalError("Unexpected IllegalAccessException"); 335 } 336 } 337 } 338 } 339 340 //------------------------------------------------------------------------- 341 342 /** 343 * <p>Adds the result of <code>super.equals()</code> to this builder.</p> 344 * 345 * @param superEquals the result of calling <code>super.equals()</code> 346 * @return EqualsBuilder - used to chain calls. 347 * @since 2.0 348 */ 349 public EqualsBuilder appendSuper(boolean superEquals) { 350 if (isEquals == false) { 351 return this; 352 } 353 isEquals = superEquals; 354 return this; 355 } 356 357 //------------------------------------------------------------------------- 358 359 /** 360 * <p>Test if two <code>Object</code>s are equal using their 361 * <code>equals</code> method.</p> 362 * 363 * @param lhs the left hand object 364 * @param rhs the right hand object 365 * @return EqualsBuilder - used to chain calls. 366 */ 367 public EqualsBuilder append(Object lhs, Object rhs) { 368 if (isEquals == false) { 369 return this; 370 } 371 if (lhs == rhs) { 372 return this; 373 } 374 if (lhs == null || rhs == null) { 375 this.setEquals(false); 376 return this; 377 } 378 Class lhsClass = lhs.getClass(); 379 if (!lhsClass.isArray()) { 380 if (lhs instanceof java.math.BigDecimal) { 381 isEquals = (((java.math.BigDecimal)lhs).compareTo(rhs) == 0); 382 } else { 383 // The simple case, not an array, just test the element 384 isEquals = lhs.equals(rhs); 385 } 386 } else if (lhs.getClass() != rhs.getClass()) { 387 // Here when we compare different dimensions, for example: a boolean[][] to a boolean[] 388 this.setEquals(false); 389 } 390 // 'Switch' on type of array, to dispatch to the correct handler 391 // This handles multi dimensional arrays of the same depth 392 else if (lhs instanceof long[]) { 393 append((long[]) lhs, (long[]) rhs); 394 } else if (lhs instanceof int[]) { 395 append((int[]) lhs, (int[]) rhs); 396 } else if (lhs instanceof short[]) { 397 append((short[]) lhs, (short[]) rhs); 398 } else if (lhs instanceof char[]) { 399 append((char[]) lhs, (char[]) rhs); 400 } else if (lhs instanceof byte[]) { 401 append((byte[]) lhs, (byte[]) rhs); 402 } else if (lhs instanceof double[]) { 403 append((double[]) lhs, (double[]) rhs); 404 } else if (lhs instanceof float[]) { 405 append((float[]) lhs, (float[]) rhs); 406 } else if (lhs instanceof boolean[]) { 407 append((boolean[]) lhs, (boolean[]) rhs); 408 } else { 409 // Not an array of primitives 410 append((Object[]) lhs, (Object[]) rhs); 411 } 412 return this; 413 } 414 415 /** 416 * <p> 417 * Test if two <code>long</code> s are equal. 418 * </p> 419 * 420 * @param lhs 421 * the left hand <code>long</code> 422 * @param rhs 423 * the right hand <code>long</code> 424 * @return EqualsBuilder - used to chain calls. 425 */ 426 public EqualsBuilder append(long lhs, long rhs) { 427 if (isEquals == false) { 428 return this; 429 } 430 isEquals = (lhs == rhs); 431 return this; 432 } 433 434 /** 435 * <p>Test if two <code>int</code>s are equal.</p> 436 * 437 * @param lhs the left hand <code>int</code> 438 * @param rhs the right hand <code>int</code> 439 * @return EqualsBuilder - used to chain calls. 440 */ 441 public EqualsBuilder append(int lhs, int rhs) { 442 if (isEquals == false) { 443 return this; 444 } 445 isEquals = (lhs == rhs); 446 return this; 447 } 448 449 /** 450 * <p>Test if two <code>short</code>s are equal.</p> 451 * 452 * @param lhs the left hand <code>short</code> 453 * @param rhs the right hand <code>short</code> 454 * @return EqualsBuilder - used to chain calls. 455 */ 456 public EqualsBuilder append(short lhs, short rhs) { 457 if (isEquals == false) { 458 return this; 459 } 460 isEquals = (lhs == rhs); 461 return this; 462 } 463 464 /** 465 * <p>Test if two <code>char</code>s are equal.</p> 466 * 467 * @param lhs the left hand <code>char</code> 468 * @param rhs the right hand <code>char</code> 469 * @return EqualsBuilder - used to chain calls. 470 */ 471 public EqualsBuilder append(char lhs, char rhs) { 472 if (isEquals == false) { 473 return this; 474 } 475 isEquals = (lhs == rhs); 476 return this; 477 } 478 479 /** 480 * <p>Test if two <code>byte</code>s are equal.</p> 481 * 482 * @param lhs the left hand <code>byte</code> 483 * @param rhs the right hand <code>byte</code> 484 * @return EqualsBuilder - used to chain calls. 485 */ 486 public EqualsBuilder append(byte lhs, byte rhs) { 487 if (isEquals == false) { 488 return this; 489 } 490 isEquals = (lhs == rhs); 491 return this; 492 } 493 494 /** 495 * <p>Test if two <code>double</code>s are equal by testing that the 496 * pattern of bits returned by <code>doubleToLong</code> are equal.</p> 497 * 498 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 499 * 500 * <p>It is compatible with the hash code generated by 501 * <code>HashCodeBuilder</code>.</p> 502 * 503 * @param lhs the left hand <code>double</code> 504 * @param rhs the right hand <code>double</code> 505 * @return EqualsBuilder - used to chain calls. 506 */ 507 public EqualsBuilder append(double lhs, double rhs) { 508 if (isEquals == false) { 509 return this; 510 } 511 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs)); 512 } 513 514 /** 515 * <p>Test if two <code>float</code>s are equal byt testing that the 516 * pattern of bits returned by doubleToLong are equal.</p> 517 * 518 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p> 519 * 520 * <p>It is compatible with the hash code generated by 521 * <code>HashCodeBuilder</code>.</p> 522 * 523 * @param lhs the left hand <code>float</code> 524 * @param rhs the right hand <code>float</code> 525 * @return EqualsBuilder - used to chain calls. 526 */ 527 public EqualsBuilder append(float lhs, float rhs) { 528 if (isEquals == false) { 529 return this; 530 } 531 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs)); 532 } 533 534 /** 535 * <p>Test if two <code>booleans</code>s are equal.</p> 536 * 537 * @param lhs the left hand <code>boolean</code> 538 * @param rhs the right hand <code>boolean</code> 539 * @return EqualsBuilder - used to chain calls. 540 */ 541 public EqualsBuilder append(boolean lhs, boolean rhs) { 542 if (isEquals == false) { 543 return this; 544 } 545 isEquals = (lhs == rhs); 546 return this; 547 } 548 549 /** 550 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p> 551 * 552 * <p>This also will be called for the top level of 553 * multi-dimensional, ragged, and multi-typed arrays.</p> 554 * 555 * @param lhs the left hand <code>Object[]</code> 556 * @param rhs the right hand <code>Object[]</code> 557 * @return EqualsBuilder - used to chain calls. 558 */ 559 public EqualsBuilder append(Object[] lhs, Object[] rhs) { 560 if (isEquals == false) { 561 return this; 562 } 563 if (lhs == rhs) { 564 return this; 565 } 566 if (lhs == null || rhs == null) { 567 this.setEquals(false); 568 return this; 569 } 570 if (lhs.length != rhs.length) { 571 this.setEquals(false); 572 return this; 573 } 574 for (int i = 0; i < lhs.length && isEquals; ++i) { 575 append(lhs[i], rhs[i]); 576 } 577 return this; 578 } 579 580 /** 581 * <p>Deep comparison of array of <code>long</code>. Length and all 582 * values are compared.</p> 583 * 584 * <p>The method {@link #append(long, long)} is used.</p> 585 * 586 * @param lhs the left hand <code>long[]</code> 587 * @param rhs the right hand <code>long[]</code> 588 * @return EqualsBuilder - used to chain calls. 589 */ 590 public EqualsBuilder append(long[] lhs, long[] rhs) { 591 if (isEquals == false) { 592 return this; 593 } 594 if (lhs == rhs) { 595 return this; 596 } 597 if (lhs == null || rhs == null) { 598 this.setEquals(false); 599 return this; 600 } 601 if (lhs.length != rhs.length) { 602 this.setEquals(false); 603 return this; 604 } 605 for (int i = 0; i < lhs.length && isEquals; ++i) { 606 append(lhs[i], rhs[i]); 607 } 608 return this; 609 } 610 611 /** 612 * <p>Deep comparison of array of <code>int</code>. Length and all 613 * values are compared.</p> 614 * 615 * <p>The method {@link #append(int, int)} is used.</p> 616 * 617 * @param lhs the left hand <code>int[]</code> 618 * @param rhs the right hand <code>int[]</code> 619 * @return EqualsBuilder - used to chain calls. 620 */ 621 public EqualsBuilder append(int[] lhs, int[] rhs) { 622 if (isEquals == false) { 623 return this; 624 } 625 if (lhs == rhs) { 626 return this; 627 } 628 if (lhs == null || rhs == null) { 629 this.setEquals(false); 630 return this; 631 } 632 if (lhs.length != rhs.length) { 633 this.setEquals(false); 634 return this; 635 } 636 for (int i = 0; i < lhs.length && isEquals; ++i) { 637 append(lhs[i], rhs[i]); 638 } 639 return this; 640 } 641 642 /** 643 * <p>Deep comparison of array of <code>short</code>. Length and all 644 * values are compared.</p> 645 * 646 * <p>The method {@link #append(short, short)} is used.</p> 647 * 648 * @param lhs the left hand <code>short[]</code> 649 * @param rhs the right hand <code>short[]</code> 650 * @return EqualsBuilder - used to chain calls. 651 */ 652 public EqualsBuilder append(short[] lhs, short[] rhs) { 653 if (isEquals == false) { 654 return this; 655 } 656 if (lhs == rhs) { 657 return this; 658 } 659 if (lhs == null || rhs == null) { 660 this.setEquals(false); 661 return this; 662 } 663 if (lhs.length != rhs.length) { 664 this.setEquals(false); 665 return this; 666 } 667 for (int i = 0; i < lhs.length && isEquals; ++i) { 668 append(lhs[i], rhs[i]); 669 } 670 return this; 671 } 672 673 /** 674 * <p>Deep comparison of array of <code>char</code>. Length and all 675 * values are compared.</p> 676 * 677 * <p>The method {@link #append(char, char)} is used.</p> 678 * 679 * @param lhs the left hand <code>char[]</code> 680 * @param rhs the right hand <code>char[]</code> 681 * @return EqualsBuilder - used to chain calls. 682 */ 683 public EqualsBuilder append(char[] lhs, char[] rhs) { 684 if (isEquals == false) { 685 return this; 686 } 687 if (lhs == rhs) { 688 return this; 689 } 690 if (lhs == null || rhs == null) { 691 this.setEquals(false); 692 return this; 693 } 694 if (lhs.length != rhs.length) { 695 this.setEquals(false); 696 return this; 697 } 698 for (int i = 0; i < lhs.length && isEquals; ++i) { 699 append(lhs[i], rhs[i]); 700 } 701 return this; 702 } 703 704 /** 705 * <p>Deep comparison of array of <code>byte</code>. Length and all 706 * values are compared.</p> 707 * 708 * <p>The method {@link #append(byte, byte)} is used.</p> 709 * 710 * @param lhs the left hand <code>byte[]</code> 711 * @param rhs the right hand <code>byte[]</code> 712 * @return EqualsBuilder - used to chain calls. 713 */ 714 public EqualsBuilder append(byte[] lhs, byte[] rhs) { 715 if (isEquals == false) { 716 return this; 717 } 718 if (lhs == rhs) { 719 return this; 720 } 721 if (lhs == null || rhs == null) { 722 this.setEquals(false); 723 return this; 724 } 725 if (lhs.length != rhs.length) { 726 this.setEquals(false); 727 return this; 728 } 729 for (int i = 0; i < lhs.length && isEquals; ++i) { 730 append(lhs[i], rhs[i]); 731 } 732 return this; 733 } 734 735 /** 736 * <p>Deep comparison of array of <code>double</code>. Length and all 737 * values are compared.</p> 738 * 739 * <p>The method {@link #append(double, double)} is used.</p> 740 * 741 * @param lhs the left hand <code>double[]</code> 742 * @param rhs the right hand <code>double[]</code> 743 * @return EqualsBuilder - used to chain calls. 744 */ 745 public EqualsBuilder append(double[] lhs, double[] rhs) { 746 if (isEquals == false) { 747 return this; 748 } 749 if (lhs == rhs) { 750 return this; 751 } 752 if (lhs == null || rhs == null) { 753 this.setEquals(false); 754 return this; 755 } 756 if (lhs.length != rhs.length) { 757 this.setEquals(false); 758 return this; 759 } 760 for (int i = 0; i < lhs.length && isEquals; ++i) { 761 append(lhs[i], rhs[i]); 762 } 763 return this; 764 } 765 766 /** 767 * <p>Deep comparison of array of <code>float</code>. Length and all 768 * values are compared.</p> 769 * 770 * <p>The method {@link #append(float, float)} is used.</p> 771 * 772 * @param lhs the left hand <code>float[]</code> 773 * @param rhs the right hand <code>float[]</code> 774 * @return EqualsBuilder - used to chain calls. 775 */ 776 public EqualsBuilder append(float[] lhs, float[] rhs) { 777 if (isEquals == false) { 778 return this; 779 } 780 if (lhs == rhs) { 781 return this; 782 } 783 if (lhs == null || rhs == null) { 784 this.setEquals(false); 785 return this; 786 } 787 if (lhs.length != rhs.length) { 788 this.setEquals(false); 789 return this; 790 } 791 for (int i = 0; i < lhs.length && isEquals; ++i) { 792 append(lhs[i], rhs[i]); 793 } 794 return this; 795 } 796 797 /** 798 * <p>Deep comparison of array of <code>boolean</code>. Length and all 799 * values are compared.</p> 800 * 801 * <p>The method {@link #append(boolean, boolean)} is used.</p> 802 * 803 * @param lhs the left hand <code>boolean[]</code> 804 * @param rhs the right hand <code>boolean[]</code> 805 * @return EqualsBuilder - used to chain calls. 806 */ 807 public EqualsBuilder append(boolean[] lhs, boolean[] rhs) { 808 if (isEquals == false) { 809 return this; 810 } 811 if (lhs == rhs) { 812 return this; 813 } 814 if (lhs == null || rhs == null) { 815 this.setEquals(false); 816 return this; 817 } 818 if (lhs.length != rhs.length) { 819 this.setEquals(false); 820 return this; 821 } 822 for (int i = 0; i < lhs.length && isEquals; ++i) { 823 append(lhs[i], rhs[i]); 824 } 825 return this; 826 } 827 828 /** 829 * <p>Returns <code>true</code> if the fields that have been checked 830 * are all equal.</p> 831 * 832 * @return boolean 833 */ 834 public boolean isEquals() { 835 return this.isEquals; 836 } 837 838 /** 839 * Sets the <code>isEquals</code> value. 840 * 841 * @param isEquals The value to set. 842 * @since 2.1 843 */ 844 protected void setEquals(boolean isEquals) { 845 this.isEquals = isEquals; 846 } 847 }