Home | History | Annotate | Download | only in apachecommons
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 
      6 //NON-STANDARD LICENCE HEADER HERE - THAT'S OK
      7 //Class comes from Apache Commons Lang, added some tiny changes
      8 package org.mockito.internal.matchers.apachecommons;
      9 
     10 import java.lang.reflect.AccessibleObject;
     11 import java.lang.reflect.Field;
     12 import java.lang.reflect.Modifier;
     13 import java.util.Arrays;
     14 import java.util.Collections;
     15 import java.util.List;
     16 
     17 /**
     18  * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
     19  *
     20  * <p> This class provides methods to build a good equals method for any
     21  * class. It follows rules laid out in
     22  * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
     23  * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
     24  * <code>floats</code>, and arrays can be tricky. Also, making sure that
     25  * <code>equals()</code> and <code>hashCode()</code> are consistent can be
     26  * difficult.</p>
     27  *
     28  * <p>Two Objects that compare as equals must generate the same hash code,
     29  * but two Objects with the same hash code do not have to be equal.</p>
     30  *
     31  * <p>All relevant fields should be included in the calculation of equals.
     32  * Derived fields may be ignored. In particular, any field used in
     33  * generating a hash code must be used in the equals method, and vice
     34  * versa.</p>
     35  *
     36  * <p>Typical use for the code is as follows:</p>
     37  * <pre class="code"><code class="java">
     38  * public boolean equals(Object obj) {
     39  *   if (obj == null) { return false; }
     40  *   if (obj == this) { return true; }
     41  *   if (obj.getClass() != getClass()) {
     42  *     return false;
     43  *   }
     44  *   MyClass rhs = (MyClass) obj;
     45  *   return new EqualsBuilder()
     46  *                 .appendSuper(super.equals(obj))
     47  *                 .append(field1, rhs.field1)
     48  *                 .append(field2, rhs.field2)
     49  *                 .append(field3, rhs.field3)
     50  *                 .isEquals();
     51  *  }
     52  * </code></pre>
     53  *
     54  * <p> Alternatively, there is a method that uses reflection to determine
     55  * the fields to test. Because these fields are usually private, the method,
     56  * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
     57  * change the visibility of the fields. This will fail under a security
     58  * manager, unless the appropriate permissions are set up correctly. It is
     59  * also slower than testing explicitly.</p>
     60  *
     61  * <p> A typical invocation for this method would look like:</p>
     62  * <pre class="code"><code class="java">
     63  * public boolean equals(Object obj) {
     64  *   return EqualsBuilder.reflectionEquals(this, obj);
     65  * }
     66  * </code></pre>
     67  *
     68  * @author <a href="mailto:steve.downey (at) netfolio.com">Steve Downey</a>
     69  * @author Stephen Colebourne
     70  * @author Gary Gregory
     71  * @author Pete Gieser
     72  * @author Arun Mammen Thomas
     73  * @since 1.0
     74  * @version $Id: EqualsBuilder.java 611543 2008-01-13 07:00:22Z bayard $
     75  */
     76 @SuppressWarnings("unchecked")
     77 class EqualsBuilder {
     78 
     79     /**
     80      * If the fields tested are equals.
     81      * The default value is <code>true</code>.
     82      */
     83     private boolean isEquals = true;
     84 
     85     /**
     86      * <p>Constructor for EqualsBuilder.</p>
     87      *
     88      * <p>Starts off assuming that equals is <code>true</code>.</p>
     89      * @see Object#equals(Object)
     90      */
     91     public EqualsBuilder() {
     92         // do nothing for now.
     93     }
     94 
     95     //-------------------------------------------------------------------------
     96 
     97     /**
     98      * <p>This method uses reflection to determine if the two <code>Object</code>s
     99      * are equal.</p>
    100      *
    101      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    102      * fields. This means that it will throw a security exception if run under
    103      * a security manager, if the permissions are not set up correctly. It is also
    104      * not as efficient as testing explicitly.</p>
    105      *
    106      * <p>Transient members will be not be tested, as they are likely derived
    107      * fields, and not part of the value of the Object.</p>
    108      *
    109      * <p>Static fields will not be tested. Superclass fields will be included.</p>
    110      *
    111      * @param lhs  <code>this</code> object
    112      * @param rhs  the other object
    113      * @return <code>true</code> if the two Objects have tested equals.
    114      */
    115     public static boolean reflectionEquals(Object lhs, Object rhs) {
    116         return reflectionEquals(lhs, rhs, false, null, null);
    117     }
    118 
    119     /**
    120      * <p>This method uses reflection to determine if the two <code>Object</code>s
    121      * are equal.</p>
    122      *
    123      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    124      * fields. This means that it will throw a security exception if run under
    125      * a security manager, if the permissions are not set up correctly. It is also
    126      * not as efficient as testing explicitly.</p>
    127      *
    128      * <p>Transient members will be not be tested, as they are likely derived
    129      * fields, and not part of the value of the Object.</p>
    130      *
    131      * <p>Static fields will not be tested. Superclass fields will be included.</p>
    132      *
    133      * @param lhs  <code>this</code> object
    134      * @param rhs  the other object
    135      * @param excludeFields  array of field names to exclude from testing
    136      * @return <code>true</code> if the two Objects have tested equals.
    137      */
    138     public static boolean reflectionEquals(Object lhs, Object rhs, String[] excludeFields) {
    139         return reflectionEquals(lhs, rhs, false, null, excludeFields);
    140     }
    141 
    142     /**
    143      * <p>This method uses reflection to determine if the two <code>Object</code>s
    144      * are equal.</p>
    145      *
    146      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    147      * fields. This means that it will throw a security exception if run under
    148      * a security manager, if the permissions are not set up correctly. It is also
    149      * not as efficient as testing explicitly.</p>
    150      *
    151      * <p>If the TestTransients parameter is set to <code>true</code>, transient
    152      * members will be tested, otherwise they are ignored, as they are likely
    153      * derived fields, and not part of the value of the <code>Object</code>.</p>
    154      *
    155      * <p>Static fields will not be tested. Superclass fields will be included.</p>
    156      *
    157      * @param lhs  <code>this</code> object
    158      * @param rhs  the other object
    159      * @param testTransients  whether to include transient fields
    160      * @return <code>true</code> if the two Objects have tested equals.
    161      */
    162     public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
    163         return reflectionEquals(lhs, rhs, testTransients, null, null);
    164     }
    165 
    166     /**
    167      * <p>This method uses reflection to determine if the two <code>Object</code>s
    168      * are equal.</p>
    169      *
    170      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    171      * fields. This means that it will throw a security exception if run under
    172      * a security manager, if the permissions are not set up correctly. It is also
    173      * not as efficient as testing explicitly.</p>
    174      *
    175      * <p>If the testTransients parameter is set to <code>true</code>, transient
    176      * members will be tested, otherwise they are ignored, as they are likely
    177      * derived fields, and not part of the value of the <code>Object</code>.</p>
    178      *
    179      * <p>Static fields will not be included. Superclass fields will be appended
    180      * up to and including the specified superclass. A null superclass is treated
    181      * as java.lang.Object.</p>
    182      *
    183      * @param lhs  <code>this</code> object
    184      * @param rhs  the other object
    185      * @param testTransients  whether to include transient fields
    186      * @param reflectUpToClass  the superclass to reflect up to (inclusive),
    187      *  may be <code>null</code>
    188      * @return <code>true</code> if the two Objects have tested equals.
    189      * @since 2.0
    190      */
    191     public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass) {
    192         return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, null);
    193     }
    194 
    195     /**
    196      * <p>This method uses reflection to determine if the two <code>Object</code>s
    197      * are equal.</p>
    198      *
    199      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    200      * fields. This means that it will throw a security exception if run under
    201      * a security manager, if the permissions are not set up correctly. It is also
    202      * not as efficient as testing explicitly.</p>
    203      *
    204      * <p>If the testTransients parameter is set to <code>true</code>, transient
    205      * members will be tested, otherwise they are ignored, as they are likely
    206      * derived fields, and not part of the value of the <code>Object</code>.</p>
    207      *
    208      * <p>Static fields will not be included. Superclass fields will be appended
    209      * up to and including the specified superclass. A null superclass is treated
    210      * as java.lang.Object.</p>
    211      *
    212      * @param lhs  <code>this</code> object
    213      * @param rhs  the other object
    214      * @param testTransients  whether to include transient fields
    215      * @param reflectUpToClass  the superclass to reflect up to (inclusive),
    216      *  may be <code>null</code>
    217      * @param excludeFields  array of field names to exclude from testing
    218      * @return <code>true</code> if the two Objects have tested equals.
    219      * @since 2.0
    220      */
    221     public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass,
    222             String[] excludeFields) {
    223         if (lhs == rhs) {
    224             return true;
    225         }
    226         if (lhs == null || rhs == null) {
    227             return false;
    228         }
    229         // Find the leaf class since there may be transients in the leaf
    230         // class or in classes between the leaf and root.
    231         // If we are not testing transients or a subclass has no ivars,
    232         // then a subclass can test equals to a superclass.
    233         Class lhsClass = lhs.getClass();
    234         Class rhsClass = rhs.getClass();
    235         Class testClass;
    236         if (lhsClass.isInstance(rhs)) {
    237             testClass = lhsClass;
    238             if (!rhsClass.isInstance(lhs)) {
    239                 // rhsClass is a subclass of lhsClass
    240                 testClass = rhsClass;
    241             }
    242         } else if (rhsClass.isInstance(lhs)) {
    243             testClass = rhsClass;
    244             if (!lhsClass.isInstance(rhs)) {
    245                 // lhsClass is a subclass of rhsClass
    246                 testClass = lhsClass;
    247             }
    248         } else {
    249             // The two classes are not related.
    250             return false;
    251         }
    252         EqualsBuilder equalsBuilder = new EqualsBuilder();
    253         try {
    254             reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
    255             while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
    256                 testClass = testClass.getSuperclass();
    257                 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
    258             }
    259         } catch (IllegalArgumentException e) {
    260             // In this case, we tried to test a subclass vs. a superclass and
    261             // the subclass has ivars or the ivars are transient and
    262             // we are testing transients.
    263             // If a subclass has ivars that we are trying to test them, we get an
    264             // exception and we know that the objects are not equal.
    265             return false;
    266         }
    267         return equalsBuilder.isEquals();
    268     }
    269 
    270     /**
    271      * <p>Appends the fields and values defined by the given object of the
    272      * given Class.</p>
    273      *
    274      * @param lhs  the left hand object
    275      * @param rhs  the right hand object
    276      * @param clazz  the class to append details of
    277      * @param builder  the builder to append to
    278      * @param useTransients  whether to test transient fields
    279      * @param excludeFields  array of field names to exclude from testing
    280      */
    281     private static void reflectionAppend(
    282         Object lhs,
    283         Object rhs,
    284         Class clazz,
    285         EqualsBuilder builder,
    286         boolean useTransients,
    287         String[] excludeFields) {
    288         Field[] fields = clazz.getDeclaredFields();
    289         List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) : Collections.EMPTY_LIST;
    290         AccessibleObject.setAccessible(fields, true);
    291         for (int i = 0; i < fields.length && builder.isEquals; i++) {
    292             Field f = fields[i];
    293             if (!excludedFieldList.contains(f.getName())
    294                 && (f.getName().indexOf('$') == -1)
    295                 && (useTransients || !Modifier.isTransient(f.getModifiers()))
    296                 && (!Modifier.isStatic(f.getModifiers()))) {
    297                 try {
    298                     builder.append(f.get(lhs), f.get(rhs));
    299                 } catch (IllegalAccessException e) {
    300                     //this can't happen. Would get a Security exception instead
    301                     //throw a runtime exception in case the impossible happens.
    302                     throw new InternalError("Unexpected IllegalAccessException");
    303                 }
    304             }
    305         }
    306     }
    307 
    308     //-------------------------------------------------------------------------
    309 
    310     /**
    311      * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
    312      *
    313      * @param superEquals  the result of calling <code>super.equals()</code>
    314      * @return EqualsBuilder - used to chain calls.
    315      * @since 2.0
    316      */
    317     public EqualsBuilder appendSuper(boolean superEquals) {
    318         if (isEquals == false) {
    319             return this;
    320         }
    321         isEquals = superEquals;
    322         return this;
    323     }
    324 
    325     //-------------------------------------------------------------------------
    326 
    327     /**
    328      * <p>Test if two <code>Object</code>s are equal using their
    329      * <code>equals</code> method.</p>
    330      *
    331      * @param lhs  the left hand object
    332      * @param rhs  the right hand object
    333      * @return EqualsBuilder - used to chain calls.
    334      */
    335     public EqualsBuilder append(Object lhs, Object rhs) {
    336         if (isEquals == false) {
    337             return this;
    338         }
    339         if (lhs == rhs) {
    340             return this;
    341         }
    342         if (lhs == null || rhs == null) {
    343             this.setEquals(false);
    344             return this;
    345         }
    346         Class lhsClass = lhs.getClass();
    347         if (!lhsClass.isArray()) {
    348             if (lhs instanceof java.math.BigDecimal && rhs instanceof java.math.BigDecimal) {
    349                 isEquals = (((java.math.BigDecimal) lhs).compareTo((java.math.BigDecimal) rhs) == 0);
    350             } else {
    351                 // The simple case, not an array, just test the element
    352                 isEquals = lhs.equals(rhs);
    353             }
    354         } else if (lhs.getClass() != rhs.getClass()) {
    355             // Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
    356             this.setEquals(false);
    357 
    358         // 'Switch' on type of array, to dispatch to the correct handler
    359         // This handles multi dimensional arrays of the same depth
    360         } else if (lhs instanceof long[]) {
    361             append((long[]) lhs, (long[]) rhs);
    362         } else if (lhs instanceof int[]) {
    363             append((int[]) lhs, (int[]) rhs);
    364         } else if (lhs instanceof short[]) {
    365             append((short[]) lhs, (short[]) rhs);
    366         } else if (lhs instanceof char[]) {
    367             append((char[]) lhs, (char[]) rhs);
    368         } else if (lhs instanceof byte[]) {
    369             append((byte[]) lhs, (byte[]) rhs);
    370         } else if (lhs instanceof double[]) {
    371             append((double[]) lhs, (double[]) rhs);
    372         } else if (lhs instanceof float[]) {
    373             append((float[]) lhs, (float[]) rhs);
    374         } else if (lhs instanceof boolean[]) {
    375             append((boolean[]) lhs, (boolean[]) rhs);
    376         } else {
    377             // Not an array of primitives
    378             append((Object[]) lhs, (Object[]) rhs);
    379         }
    380         return this;
    381     }
    382 
    383     /**
    384      * <p>
    385      * Test if two <code>long</code> s are equal.
    386      * </p>
    387      *
    388      * @param lhs
    389      *                  the left hand <code>long</code>
    390      * @param rhs
    391      *                  the right hand <code>long</code>
    392      * @return EqualsBuilder - used to chain calls.
    393      */
    394     public EqualsBuilder append(long lhs, long rhs) {
    395         if (isEquals == false) {
    396             return this;
    397         }
    398         isEquals = (lhs == rhs);
    399         return this;
    400     }
    401 
    402     /**
    403      * <p>Test if two <code>int</code>s are equal.</p>
    404      *
    405      * @param lhs  the left hand <code>int</code>
    406      * @param rhs  the right hand <code>int</code>
    407      * @return EqualsBuilder - used to chain calls.
    408      */
    409     public EqualsBuilder append(int lhs, int rhs) {
    410         if (isEquals == false) {
    411             return this;
    412         }
    413         isEquals = (lhs == rhs);
    414         return this;
    415     }
    416 
    417     /**
    418      * <p>Test if two <code>short</code>s are equal.</p>
    419      *
    420      * @param lhs  the left hand <code>short</code>
    421      * @param rhs  the right hand <code>short</code>
    422      * @return EqualsBuilder - used to chain calls.
    423      */
    424     public EqualsBuilder append(short lhs, short rhs) {
    425         if (isEquals == false) {
    426             return this;
    427         }
    428         isEquals = (lhs == rhs);
    429         return this;
    430     }
    431 
    432     /**
    433      * <p>Test if two <code>char</code>s are equal.</p>
    434      *
    435      * @param lhs  the left hand <code>char</code>
    436      * @param rhs  the right hand <code>char</code>
    437      * @return EqualsBuilder - used to chain calls.
    438      */
    439     public EqualsBuilder append(char lhs, char rhs) {
    440         if (isEquals == false) {
    441             return this;
    442         }
    443         isEquals = (lhs == rhs);
    444         return this;
    445     }
    446 
    447     /**
    448      * <p>Test if two <code>byte</code>s are equal.</p>
    449      *
    450      * @param lhs  the left hand <code>byte</code>
    451      * @param rhs  the right hand <code>byte</code>
    452      * @return EqualsBuilder - used to chain calls.
    453      */
    454     public EqualsBuilder append(byte lhs, byte rhs) {
    455         if (isEquals == false) {
    456             return this;
    457         }
    458         isEquals = (lhs == rhs);
    459         return this;
    460     }
    461 
    462     /**
    463      * <p>Test if two <code>double</code>s are equal by testing that the
    464      * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
    465      *
    466      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
    467      *
    468      * <p>It is compatible with the hash code generated by
    469      * <code>HashCodeBuilder</code>.</p>
    470      *
    471      * @param lhs  the left hand <code>double</code>
    472      * @param rhs  the right hand <code>double</code>
    473      * @return EqualsBuilder - used to chain calls.
    474      */
    475     public EqualsBuilder append(double lhs, double rhs) {
    476         if (isEquals == false) {
    477             return this;
    478         }
    479         return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
    480     }
    481 
    482     /**
    483      * <p>Test if two <code>float</code>s are equal byt testing that the
    484      * pattern of bits returned by doubleToLong are equal.</p>
    485      *
    486      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
    487      *
    488      * <p>It is compatible with the hash code generated by
    489      * <code>HashCodeBuilder</code>.</p>
    490      *
    491      * @param lhs  the left hand <code>float</code>
    492      * @param rhs  the right hand <code>float</code>
    493      * @return EqualsBuilder - used to chain calls.
    494      */
    495     public EqualsBuilder append(float lhs, float rhs) {
    496         if (isEquals == false) {
    497             return this;
    498         }
    499         return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
    500     }
    501 
    502     /**
    503      * <p>Test if two <code>booleans</code>s are equal.</p>
    504      *
    505      * @param lhs  the left hand <code>boolean</code>
    506      * @param rhs  the right hand <code>boolean</code>
    507      * @return EqualsBuilder - used to chain calls.
    508       */
    509     public EqualsBuilder append(boolean lhs, boolean rhs) {
    510         if (isEquals == false) {
    511             return this;
    512         }
    513         isEquals = (lhs == rhs);
    514         return this;
    515     }
    516 
    517     /**
    518      * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
    519      *
    520      * <p>This also will be called for the top level of
    521      * multi-dimensional, ragged, and multi-typed arrays.</p>
    522      *
    523      * @param lhs  the left hand <code>Object[]</code>
    524      * @param rhs  the right hand <code>Object[]</code>
    525      * @return EqualsBuilder - used to chain calls.
    526      */
    527     public EqualsBuilder append(Object[] lhs, Object[] rhs) {
    528         if (isEquals == false) {
    529             return this;
    530         }
    531         if (lhs == rhs) {
    532             return this;
    533         }
    534         if (lhs == null || rhs == null) {
    535             this.setEquals(false);
    536             return this;
    537         }
    538         if (lhs.length != rhs.length) {
    539             this.setEquals(false);
    540             return this;
    541         }
    542         for (int i = 0; i < lhs.length && isEquals; ++i) {
    543             append(lhs[i], rhs[i]);
    544         }
    545         return this;
    546     }
    547 
    548     /**
    549      * <p>Deep comparison of array of <code>long</code>. Length and all
    550      * values are compared.</p>
    551      *
    552      * <p>The method {@link #append(long, long)} is used.</p>
    553      *
    554      * @param lhs  the left hand <code>long[]</code>
    555      * @param rhs  the right hand <code>long[]</code>
    556      * @return EqualsBuilder - used to chain calls.
    557      */
    558     public EqualsBuilder append(long[] lhs, long[] rhs) {
    559         if (isEquals == false) {
    560             return this;
    561         }
    562         if (lhs == rhs) {
    563             return this;
    564         }
    565         if (lhs == null || rhs == null) {
    566             this.setEquals(false);
    567             return this;
    568         }
    569         if (lhs.length != rhs.length) {
    570             this.setEquals(false);
    571             return this;
    572         }
    573         for (int i = 0; i < lhs.length && isEquals; ++i) {
    574             append(lhs[i], rhs[i]);
    575         }
    576         return this;
    577     }
    578 
    579     /**
    580      * <p>Deep comparison of array of <code>int</code>. Length and all
    581      * values are compared.</p>
    582      *
    583      * <p>The method {@link #append(int, int)} is used.</p>
    584      *
    585      * @param lhs  the left hand <code>int[]</code>
    586      * @param rhs  the right hand <code>int[]</code>
    587      * @return EqualsBuilder - used to chain calls.
    588      */
    589     public EqualsBuilder append(int[] lhs, int[] rhs) {
    590         if (isEquals == false) {
    591             return this;
    592         }
    593         if (lhs == rhs) {
    594             return this;
    595         }
    596         if (lhs == null || rhs == null) {
    597             this.setEquals(false);
    598             return this;
    599         }
    600         if (lhs.length != rhs.length) {
    601             this.setEquals(false);
    602             return this;
    603         }
    604         for (int i = 0; i < lhs.length && isEquals; ++i) {
    605             append(lhs[i], rhs[i]);
    606         }
    607         return this;
    608     }
    609 
    610     /**
    611      * <p>Deep comparison of array of <code>short</code>. Length and all
    612      * values are compared.</p>
    613      *
    614      * <p>The method {@link #append(short, short)} is used.</p>
    615      *
    616      * @param lhs  the left hand <code>short[]</code>
    617      * @param rhs  the right hand <code>short[]</code>
    618      * @return EqualsBuilder - used to chain calls.
    619      */
    620     public EqualsBuilder append(short[] lhs, short[] rhs) {
    621         if (isEquals == false) {
    622             return this;
    623         }
    624         if (lhs == rhs) {
    625             return this;
    626         }
    627         if (lhs == null || rhs == null) {
    628             this.setEquals(false);
    629             return this;
    630         }
    631         if (lhs.length != rhs.length) {
    632             this.setEquals(false);
    633             return this;
    634         }
    635         for (int i = 0; i < lhs.length && isEquals; ++i) {
    636             append(lhs[i], rhs[i]);
    637         }
    638         return this;
    639     }
    640 
    641     /**
    642      * <p>Deep comparison of array of <code>char</code>. Length and all
    643      * values are compared.</p>
    644      *
    645      * <p>The method {@link #append(char, char)} is used.</p>
    646      *
    647      * @param lhs  the left hand <code>char[]</code>
    648      * @param rhs  the right hand <code>char[]</code>
    649      * @return EqualsBuilder - used to chain calls.
    650      */
    651     public EqualsBuilder append(char[] lhs, char[] rhs) {
    652         if (isEquals == false) {
    653             return this;
    654         }
    655         if (lhs == rhs) {
    656             return this;
    657         }
    658         if (lhs == null || rhs == null) {
    659             this.setEquals(false);
    660             return this;
    661         }
    662         if (lhs.length != rhs.length) {
    663             this.setEquals(false);
    664             return this;
    665         }
    666         for (int i = 0; i < lhs.length && isEquals; ++i) {
    667             append(lhs[i], rhs[i]);
    668         }
    669         return this;
    670     }
    671 
    672     /**
    673      * <p>Deep comparison of array of <code>byte</code>. Length and all
    674      * values are compared.</p>
    675      *
    676      * <p>The method {@link #append(byte, byte)} is used.</p>
    677      *
    678      * @param lhs  the left hand <code>byte[]</code>
    679      * @param rhs  the right hand <code>byte[]</code>
    680      * @return EqualsBuilder - used to chain calls.
    681      */
    682     public EqualsBuilder append(byte[] lhs, byte[] rhs) {
    683         if (isEquals == false) {
    684             return this;
    685         }
    686         if (lhs == rhs) {
    687             return this;
    688         }
    689         if (lhs == null || rhs == null) {
    690             this.setEquals(false);
    691             return this;
    692         }
    693         if (lhs.length != rhs.length) {
    694             this.setEquals(false);
    695             return this;
    696         }
    697         for (int i = 0; i < lhs.length && isEquals; ++i) {
    698             append(lhs[i], rhs[i]);
    699         }
    700         return this;
    701     }
    702 
    703     /**
    704      * <p>Deep comparison of array of <code>double</code>. Length and all
    705      * values are compared.</p>
    706      *
    707      * <p>The method {@link #append(double, double)} is used.</p>
    708      *
    709      * @param lhs  the left hand <code>double[]</code>
    710      * @param rhs  the right hand <code>double[]</code>
    711      * @return EqualsBuilder - used to chain calls.
    712      */
    713     public EqualsBuilder append(double[] lhs, double[] rhs) {
    714         if (isEquals == false) {
    715             return this;
    716         }
    717         if (lhs == rhs) {
    718             return this;
    719         }
    720         if (lhs == null || rhs == null) {
    721             this.setEquals(false);
    722             return this;
    723         }
    724         if (lhs.length != rhs.length) {
    725             this.setEquals(false);
    726             return this;
    727         }
    728         for (int i = 0; i < lhs.length && isEquals; ++i) {
    729             append(lhs[i], rhs[i]);
    730         }
    731         return this;
    732     }
    733 
    734     /**
    735      * <p>Deep comparison of array of <code>float</code>. Length and all
    736      * values are compared.</p>
    737      *
    738      * <p>The method {@link #append(float, float)} is used.</p>
    739      *
    740      * @param lhs  the left hand <code>float[]</code>
    741      * @param rhs  the right hand <code>float[]</code>
    742      * @return EqualsBuilder - used to chain calls.
    743      */
    744     public EqualsBuilder append(float[] lhs, float[] rhs) {
    745         if (isEquals == false) {
    746             return this;
    747         }
    748         if (lhs == rhs) {
    749             return this;
    750         }
    751         if (lhs == null || rhs == null) {
    752             this.setEquals(false);
    753             return this;
    754         }
    755         if (lhs.length != rhs.length) {
    756             this.setEquals(false);
    757             return this;
    758         }
    759         for (int i = 0; i < lhs.length && isEquals; ++i) {
    760             append(lhs[i], rhs[i]);
    761         }
    762         return this;
    763     }
    764 
    765     /**
    766      * <p>Deep comparison of array of <code>boolean</code>. Length and all
    767      * values are compared.</p>
    768      *
    769      * <p>The method {@link #append(boolean, boolean)} is used.</p>
    770      *
    771      * @param lhs  the left hand <code>boolean[]</code>
    772      * @param rhs  the right hand <code>boolean[]</code>
    773      * @return EqualsBuilder - used to chain calls.
    774      */
    775     public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
    776         if (isEquals == false) {
    777             return this;
    778         }
    779         if (lhs == rhs) {
    780             return this;
    781         }
    782         if (lhs == null || rhs == null) {
    783             this.setEquals(false);
    784             return this;
    785         }
    786         if (lhs.length != rhs.length) {
    787             this.setEquals(false);
    788             return this;
    789         }
    790         for (int i = 0; i < lhs.length && isEquals; ++i) {
    791             append(lhs[i], rhs[i]);
    792         }
    793         return this;
    794     }
    795 
    796     /**
    797      * <p>Returns <code>true</code> if the fields that have been checked
    798      * are all equal.</p>
    799      *
    800      * @return boolean
    801      */
    802     public boolean isEquals() {
    803         return this.isEquals;
    804     }
    805 
    806     /**
    807      * Sets the <code>isEquals</code> value.
    808      *
    809      * @param isEquals The value to set.
    810      * @since 2.1
    811      */
    812     protected void setEquals(boolean isEquals) {
    813         this.isEquals = isEquals;
    814     }
    815 }
    816