    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.lang3.builder;
    018
    019    import java.lang.reflect.AccessibleObject;
    020    import java.lang.reflect.Field;
    021    import java.lang.reflect.Modifier;
    022    import java.util.Collection;
    023    import java.util.HashSet;
    024    import java.util.Set;
    025
    026    import org.apache.commons.lang3.ArrayUtils;
    027    import org.apache.commons.lang3.tuple.Pair;
    028
    029    /**
    030     * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
    031     *
    032     * <p> This class provides methods to build a good equals method for any
    033     * class. It follows rules laid out in
    034     * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
    035     * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
    036     * <code>floats</code>, and arrays can be tricky. Also, making sure that
    037     * <code>equals()</code> and <code>hashCode()</code> are consistent can be
    038     * difficult.</p>
    039     *
    040     * <p>Two Objects that compare as equals must generate the same hash code,
    041     * but two Objects with the same hash code do not have to be equal.</p>
    042     *
    043     * <p>All relevant fields should be included in the calculation of equals.
    044     * Derived fields may be ignored. In particular, any field used in
    045     * generating a hash code must be used in the equals method, and vice
    046     * versa.</p>
    047     *
    048     * <p>Typical use for the code is as follows:</p>
    049     * <pre>
    050     * public boolean equals(Object obj) {
    051     *   if (obj == null) { return false; }
    052     *   if (obj == this) { return true; }
    053     *   if (obj.getClass() != getClass()) {
    054     *     return false;
    055     *   }
    056     *   MyClass rhs = (MyClass) obj;
    057     *   return new EqualsBuilder()
    058     *                 .appendSuper(super.equals(obj))
    059     *                 .append(field1, rhs.field1)
    060     *                 .append(field2, rhs.field2)
    061     *                 .append(field3, rhs.field3)
    062     *                 .isEquals();
    063     *  }
    064     * </pre>
    065     *
    066     * <p> Alternatively, there is a method that uses reflection to determine
    067     * the fields to test. Because these fields are usually private, the method,
    068     * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
    069     * change the visibility of the fields. This will fail under a security
    070     * manager, unless the appropriate permissions are set up correctly. It is
    071     * also slower than testing explicitly.</p>
    072     *
    073     * <p> A typical invocation for this method would look like:</p>
    074     * <pre>
    075     * public boolean equals(Object obj) {
    076     *   return EqualsBuilder.reflectionEquals(this, obj);
    077     * }
    078     * </pre>
    079     *
    080     * @since 1.0
    081     * @version $Id: EqualsBuilder.java 1091531 2011-04-12 18:29:49Z ggregory $
    082     */
    083    public class EqualsBuilder implements Builder<Boolean> {
    084
    085        /**
    086         * <p>
    087         * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
    088         * </p>
    089         *
    090         * @since 3.0
    091         */
    092        private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<Set<Pair<IDKey, IDKey>>>();
    093
    094        /*
    095         * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
    096         * we are in the process of calculating.
    097         *
    098         * So we generate a one-to-one mapping from the original object to a new object.
    099         *
    100         * Now HashSet uses equals() to determine if two elements with the same hashcode really
    101         * are equal, so we also need to ensure that the replacement objects are only equal
    102         * if the original objects are identical.
    103         *
    104         * The original implementation (2.4 and before) used the System.indentityHashCode()
    105         * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
    106         *
    107         * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
    108         * to disambiguate the duplicate ids.
    109         */
    110
    111        /**
    112         * <p>
    113         * Returns the registry of object pairs being traversed by the reflection
    114         * methods in the current thread.
    115         * </p>
    116         *
    117         * @return Set the registry of objects being traversed
    118         * @since 3.0
    119         */
    120        static Set<Pair<IDKey, IDKey>> getRegistry() {
    121            return REGISTRY.get();
    122        }
    123
    124        /**
    125         * <p>
    126         * Converters value pair into a register pair.
    127         * </p>
    128         *
    129         * @param lhs <code>this</code> object
    130         * @param rhs the other object
    131         *
    132         * @return the pair
    133         */
    134        static Pair<IDKey, IDKey> getRegisterPair(Object lhs, Object rhs) {
    135            IDKey left = new IDKey(lhs);
    136            IDKey right = new IDKey(rhs);
    137            return Pair.of(left, right);
    138        }
    139
    140        /**
    141         * <p>
    142         * Returns <code>true</code> if the registry contains the given object pair.
    143         * Used by the reflection methods to avoid infinite loops.
    144         * Objects might be swapped therefore a check is needed if the object pair
    145         * is registered in given or swapped order.
    146         * </p>
    147         *
    148         * @param lhs <code>this</code> object to lookup in registry
    149         * @param rhs the other object to lookup on registry
    150         * @return boolean <code>true</code> if the registry contains the given object.
    151         * @since 3.0
    152         */
    153        static boolean isRegistered(Object lhs, Object rhs) {
    154            Set<Pair<IDKey, IDKey>> registry = getRegistry();
    155            Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
    156            Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getLeft(), pair.getRight());
    157
    158            return registry != null
    159                    && (registry.contains(pair) || registry.contains(swappedPair));
    160        }
    161
    162        /**
    163         * <p>
    164         * Registers the given object pair.
    165         * Used by the reflection methods to avoid infinite loops.
    166         * </p>
    167         *
    168         * @param lhs <code>this</code> object to register
    169         * @param rhs the other object to register
    170         */
    171        static void register(Object lhs, Object rhs) {
    172            synchronized (EqualsBuilder.class) {
    173                if (getRegistry() == null) {
    174                    REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>());
    175                }
    176            }
    177
    178            Set<Pair<IDKey, IDKey>> registry = getRegistry();
    179            Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
    180            registry.add(pair);
    181        }
    182
    183        /**
    184         * <p>
    185         * Unregisters the given object pair.
    186         * </p>
    187         *
    188         * <p>
    189         * Used by the reflection methods to avoid infinite loops.
    190         *
    191         * @param lhs <code>this</code> object to unregister
    192         * @param rhs the other object to unregister
    193         * @since 3.0
    194         */
    195        static void unregister(Object lhs, Object rhs) {
    196            Set<Pair<IDKey, IDKey>> registry = getRegistry();
    197            if (registry != null) {
    198                Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
    199                registry.remove(pair);
    200                synchronized (EqualsBuilder.class) {
    201                    //read again
    202                    registry = getRegistry();
    203                    if (registry != null && registry.isEmpty()) {
    204                        REGISTRY.remove();
    205                    }
    206                }
    207            }
    208        }
    209
    210        /**
    211         * If the fields tested are equals.
    212         * The default value is <code>true</code>.
    213         */
    214        private boolean isEquals = true;
    215
    216        /**
    217         * <p>Constructor for EqualsBuilder.</p>
    218         *
    219         * <p>Starts off assuming that equals is <code>true</code>.</p>
    220         * @see Object#equals(Object)
    221         */
    222        public EqualsBuilder() {
    223            // do nothing for now.
    224        }
    225
    226        //-------------------------------------------------------------------------
    227
    228        /**
    229         * <p>This method uses reflection to determine if the two <code>Object</code>s
    230         * are equal.</p>
    231         *
    232         * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    233         * fields. This means that it will throw a security exception if run under
    234         * a security manager, if the permissions are not set up correctly. It is also
    235         * not as efficient as testing explicitly.</p>
    236         *
    237         * <p>Transient members will be not be tested, as they are likely derived
    238         * fields, and not part of the value of the Object.</p>
    239         *
    240         * <p>Static fields will not be tested. Superclass fields will be included.</p>
    241         *
    242         * @param lhs  <code>this</code> object
    243         * @param rhs  the other object
    244         * @param excludeFields  Collection of String field names to exclude from testing
    245         * @return <code>true</code> if the two Objects have tested equals.
    246         */
    247        public static boolean reflectionEquals(Object lhs, Object rhs, Collection<String> excludeFields) {
    248            return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
    249        }
    250
    251        /**
    252         * <p>This method uses reflection to determine if the two <code>Object</code>s
    253         * are equal.</p>
    254         *
    255         * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    256         * fields. This means that it will throw a security exception if run under
    257         * a security manager, if the permissions are not set up correctly. It is also
    258         * not as efficient as testing explicitly.</p>
    259         *
    260         * <p>Transient members will be not be tested, as they are likely derived
    261         * fields, and not part of the value of the Object.</p>
    262         *
    263         * <p>Static fields will not be tested. Superclass fields will be included.</p>
    264         *
    265         * @param lhs  <code>this</code> object
    266         * @param rhs  the other object
    267         * @param excludeFields  array of field names to exclude from testing
    268         * @return <code>true</code> if the two Objects have tested equals.
    269         */
    270        public static boolean reflectionEquals(Object lhs, Object rhs, String... excludeFields) {
    271            return reflectionEquals(lhs, rhs, false, null, excludeFields);
    272        }
    273
    274        /**
    275         * <p>This method uses reflection to determine if the two <code>Object</code>s
    276         * are equal.</p>
    277         *
    278         * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    279         * fields. This means that it will throw a security exception if run under
    280         * a security manager, if the permissions are not set up correctly. It is also
    281         * not as efficient as testing explicitly.</p>
    282         *
    283         * <p>If the TestTransients parameter is set to <code>true</code>, transient
    284         * members will be tested, otherwise they are ignored, as they are likely
    285         * derived fields, and not part of the value of the <code>Object</code>.</p>
    286         *
    287         * <p>Static fields will not be tested. Superclass fields will be included.</p>
    288         *
    289         * @param lhs  <code>this</code> object
    290         * @param rhs  the other object
    291         * @param testTransients  whether to include transient fields
    292         * @return <code>true</code> if the two Objects have tested equals.
    293         */
    294        public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
    295            return reflectionEquals(lhs, rhs, testTransients, null);
    296        }
    297
    298        /**
    299         * <p>This method uses reflection to determine if the two <code>Object</code>s
    300         * are equal.</p>
    301         *
    302         * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
    303         * fields. This means that it will throw a security exception if run under
    304         * a security manager, if the permissions are not set up correctly. It is also
    305         * not as efficient as testing explicitly.</p>
    306         *
    307         * <p>If the testTransients parameter is set to <code>true</code>, transient
    308         * members will be tested, otherwise they are ignored, as they are likely
    309         * derived fields, and not part of the value of the <code>Object</code>.</p>
    310         *
    311         * <p>Static fields will not be included. Superclass fields will be appended
    312         * up to and including the specified superclass. A null superclass is treated
    313         * as java.lang.Object.</p>
    314         *
    315         * @param lhs  <code>this</code> object
    316         * @param rhs  the other object
    317         * @param testTransients  whether to include transient fields
    318         * @param reflectUpToClass  the superclass to reflect up to (inclusive),
    319         *  may be <code>null</code>
    320         * @param excludeFields  array of field names to exclude from testing
    321         * @return <code>true</code> if the two Objects have tested equals.
    322         * @since 2.0
    323         */
    324        public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass,
    325                String... excludeFields) {
    326            if (lhs == rhs) {
    327                return true;
    328            }
    329            if (lhs == null || rhs == null) {
    330                return false;
    331            }
    332            // Find the leaf class since there may be transients in the leaf
    333            // class or in classes between the leaf and root.
    334            // If we are not testing transients or a subclass has no ivars,
    335            // then a subclass can test equals to a superclass.
    336            Class<?> lhsClass = lhs.getClass();
    337            Class<?> rhsClass = rhs.getClass();
    338            Class<?> testClass;
    339            if (lhsClass.isInstance(rhs)) {
    340                testClass = lhsClass;
    341                if (!rhsClass.isInstance(lhs)) {
    342                    // rhsClass is a subclass of lhsClass
    343                    testClass = rhsClass;
    344                }
    345            } else if (rhsClass.isInstance(lhs)) {
    346                testClass = rhsClass;
    347                if (!lhsClass.isInstance(rhs)) {
    348                    // lhsClass is a subclass of rhsClass
    349                    testClass = lhsClass;
    350                }
    351            } else {
    352                // The two classes are not related.
    353                return false;
    354            }
    355            EqualsBuilder equalsBuilder = new EqualsBuilder();
    356            try {
    357                reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
    358                while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
    359                    testClass = testClass.getSuperclass();
    360                    reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
    361                }
    362            } catch (IllegalArgumentException e) {
    363                // In this case, we tried to test a subclass vs. a superclass and
    364                // the subclass has ivars or the ivars are transient and
    365                // we are testing transients.
    366                // If a subclass has ivars that we are trying to test them, we get an
    367                // exception and we know that the objects are not equal.
    368                return false;
    369            }
    370            return equalsBuilder.isEquals();
    371        }
    372
    373        /**
    374         * <p>Appends the fields and values defined by the given object of the
    375         * given Class.</p>
    376         *
    377         * @param lhs  the left hand object
    378         * @param rhs  the right hand object
    379         * @param clazz  the class to append details of
    380         * @param builder  the builder to append to
    381         * @param useTransients  whether to test transient fields
    382         * @param excludeFields  array of field names to exclude from testing
    383         */
    384        private static void reflectionAppend(
    385            Object lhs,
    386            Object rhs,
    387            Class<?> clazz,
    388            EqualsBuilder builder,
    389            boolean useTransients,
    390            String[] excludeFields) {
    391
    392            if (isRegistered(lhs, rhs)) {
    393                return;
    394            }
    395
    396            try {
    397                register(lhs, rhs);
    398                Field[] fields = clazz.getDeclaredFields();
    399                AccessibleObject.setAccessible(fields, true);
    400                for (int i = 0; i < fields.length && builder.isEquals; i++) {
    401                    Field f = fields[i];
    402                    if (!ArrayUtils.contains(excludeFields, f.getName())
    403                        && (f.getName().indexOf('$') == -1)
    404                        && (useTransients || !Modifier.isTransient(f.getModifiers()))
    405                        && (!Modifier.isStatic(f.getModifiers()))) {
    406                        try {
    407                            builder.append(f.get(lhs), f.get(rhs));
    408                        } catch (IllegalAccessException e) {
    409                            //this can't happen. Would get a Security exception instead
    410                            //throw a runtime exception in case the impossible happens.
    411                            throw new InternalError("Unexpected IllegalAccessException");
    412                        }
    413                    }
    414                }
    415            } finally {
    416                unregister(lhs, rhs);
    417            }
    418        }
    419
    420        //-------------------------------------------------------------------------
    421
    422        /**
    423         * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
    424         *
    425         * @param superEquals  the result of calling <code>super.equals()</code>
    426         * @return EqualsBuilder - used to chain calls.
    427         * @since 2.0
    428         */
    429        public EqualsBuilder appendSuper(boolean superEquals) {
    430            if (isEquals == false) {
    431                return this;
    432            }
    433            isEquals = superEquals;
    434            return this;
    435        }
    436
    437        //-------------------------------------------------------------------------
    438
    439        /**
    440         * <p>Test if two <code>Object</code>s are equal using their
    441         * <code>equals</code> method.</p>
    442         *
    443         * @param lhs  the left hand object
    444         * @param rhs  the right hand object
    445         * @return EqualsBuilder - used to chain calls.
    446         */
    447        public EqualsBuilder append(Object lhs, Object rhs) {
    448            if (isEquals == false) {
    449                return this;
    450            }
    451            if (lhs == rhs) {
    452                return this;
    453            }
    454            if (lhs == null || rhs == null) {
    455                this.setEquals(false);
    456                return this;
    457            }
    458            Class<?> lhsClass = lhs.getClass();
    459            if (!lhsClass.isArray()) {
    460                // The simple case, not an array, just test the element
    461                isEquals = lhs.equals(rhs);
    462            } else if (lhs.getClass() != rhs.getClass()) {
    463                // Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
    464                this.setEquals(false);
    465            }
    466            // 'Switch' on type of array, to dispatch to the correct handler
    467            // This handles multi dimensional arrays of the same depth
    468            else if (lhs instanceof long[]) {
    469                append((long[]) lhs, (long[]) rhs);
    470            } else if (lhs instanceof int[]) {
    471                append((int[]) lhs, (int[]) rhs);
    472            } else if (lhs instanceof short[]) {
    473                append((short[]) lhs, (short[]) rhs);
    474            } else if (lhs instanceof char[]) {
    475                append((char[]) lhs, (char[]) rhs);
    476            } else if (lhs instanceof byte[]) {
    477                append((byte[]) lhs, (byte[]) rhs);
    478            } else if (lhs instanceof double[]) {
    479                append((double[]) lhs, (double[]) rhs);
    480            } else if (lhs instanceof float[]) {
    481                append((float[]) lhs, (float[]) rhs);
    482            } else if (lhs instanceof boolean[]) {
    483                append((boolean[]) lhs, (boolean[]) rhs);
    484            } else {
    485                // Not an array of primitives
    486                append((Object[]) lhs, (Object[]) rhs);
    487            }
    488            return this;
    489        }
    490
    491        /**
    492         * <p>
    493         * Test if two <code>long</code> s are equal.
    494         * </p>
    495         *
    496         * @param lhs
    497         *                  the left hand <code>long</code>
    498         * @param rhs
    499         *                  the right hand <code>long</code>
    500         * @return EqualsBuilder - used to chain calls.
    501         */
    502        public EqualsBuilder append(long lhs, long rhs) {
    503            if (isEquals == false) {
    504                return this;
    505            }
    506            isEquals = (lhs == rhs);
    507            return this;
    508        }
    509
    510        /**
    511         * <p>Test if two <code>int</code>s are equal.</p>
    512         *
    513         * @param lhs  the left hand <code>int</code>
    514         * @param rhs  the right hand <code>int</code>
    515         * @return EqualsBuilder - used to chain calls.
    516         */
    517        public EqualsBuilder append(int lhs, int rhs) {
    518            if (isEquals == false) {
    519                return this;
    520            }
    521            isEquals = (lhs == rhs);
    522            return this;
    523        }
    524
    525        /**
    526         * <p>Test if two <code>short</code>s are equal.</p>
    527         *
    528         * @param lhs  the left hand <code>short</code>
    529         * @param rhs  the right hand <code>short</code>
    530         * @return EqualsBuilder - used to chain calls.
    531         */
    532        public EqualsBuilder append(short lhs, short rhs) {
    533            if (isEquals == false) {
    534                return this;
    535            }
    536            isEquals = (lhs == rhs);
    537            return this;
    538        }
    539
    540        /**
    541         * <p>Test if two <code>char</code>s are equal.</p>
    542         *
    543         * @param lhs  the left hand <code>char</code>
    544         * @param rhs  the right hand <code>char</code>
    545         * @return EqualsBuilder - used to chain calls.
    546         */
    547        public EqualsBuilder append(char lhs, char rhs) {
    548            if (isEquals == false) {
    549                return this;
    550            }
    551            isEquals = (lhs == rhs);
    552            return this;
    553        }
    554
    555        /**
    556         * <p>Test if two <code>byte</code>s are equal.</p>
    557         *
    558         * @param lhs  the left hand <code>byte</code>
    559         * @param rhs  the right hand <code>byte</code>
    560         * @return EqualsBuilder - used to chain calls.
    561         */
    562        public EqualsBuilder append(byte lhs, byte rhs) {
    563            if (isEquals == false) {
    564                return this;
    565            }
    566            isEquals = (lhs == rhs);
    567            return this;
    568        }
    569
    570        /**
    571         * <p>Test if two <code>double</code>s are equal by testing that the
    572         * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
    573         *
    574         * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
    575         *
    576         * <p>It is compatible with the hash code generated by
    577         * <code>HashCodeBuilder</code>.</p>
    578         *
    579         * @param lhs  the left hand <code>double</code>
    580         * @param rhs  the right hand <code>double</code>
    581         * @return EqualsBuilder - used to chain calls.
    582         */
    583        public EqualsBuilder append(double lhs, double rhs) {
    584            if (isEquals == false) {
    585                return this;
    586            }
    587            return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
    588        }
    589
    590        /**
    591         * <p>Test if two <code>float</code>s are equal byt testing that the
    592         * pattern of bits returned by doubleToLong are equal.</p>
    593         *
    594         * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
    595         *
    596         * <p>It is compatible with the hash code generated by
    597         * <code>HashCodeBuilder</code>.</p>
    598         *
    599         * @param lhs  the left hand <code>float</code>
    600         * @param rhs  the right hand <code>float</code>
    601         * @return EqualsBuilder - used to chain calls.
    602         */
    603        public EqualsBuilder append(float lhs, float rhs) {
    604            if (isEquals == false) {
    605                return this;
    606            }
    607            return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
    608        }
    609
    610        /**
    611         * <p>Test if two <code>booleans</code>s are equal.</p>
    612         *
    613         * @param lhs  the left hand <code>boolean</code>
    614         * @param rhs  the right hand <code>boolean</code>
    615         * @return EqualsBuilder - used to chain calls.
    616          */
    617        public EqualsBuilder append(boolean lhs, boolean rhs) {
    618            if (isEquals == false) {
    619                return this;
    620            }
    621            isEquals = (lhs == rhs);
    622            return this;
    623        }
    624
    625        /**
    626         * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
    627         *
    628         * <p>This also will be called for the top level of
    629         * multi-dimensional, ragged, and multi-typed arrays.</p>
    630         *
    631         * @param lhs  the left hand <code>Object[]</code>
    632         * @param rhs  the right hand <code>Object[]</code>
    633         * @return EqualsBuilder - used to chain calls.
    634         */
    635        public EqualsBuilder append(Object[] lhs, Object[] rhs) {
    636            if (isEquals == false) {
    637                return this;
    638            }
    639            if (lhs == rhs) {
    640                return this;
    641            }
    642            if (lhs == null || rhs == null) {
    643                this.setEquals(false);
    644                return this;
    645            }
    646            if (lhs.length != rhs.length) {
    647                this.setEquals(false);
    648                return this;
    649            }
    650            for (int i = 0; i < lhs.length && isEquals; ++i) {
    651                append(lhs[i], rhs[i]);
    652            }
    653            return this;
    654        }
    655
    656        /**
    657         * <p>Deep comparison of array of <code>long</code>. Length and all
    658         * values are compared.</p>
    659         *
    660         * <p>The method {@link #append(long, long)} is used.</p>
    661         *
    662         * @param lhs  the left hand <code>long[]</code>
    663         * @param rhs  the right hand <code>long[]</code>
    664         * @return EqualsBuilder - used to chain calls.
    665         */
    666        public EqualsBuilder append(long[] lhs, long[] rhs) {
    667            if (isEquals == false) {
    668                return this;
    669            }
    670            if (lhs == rhs) {
    671                return this;
    672            }
    673            if (lhs == null || rhs == null) {
    674                this.setEquals(false);
    675                return this;
    676            }
    677            if (lhs.length != rhs.length) {
    678                this.setEquals(false);
    679                return this;
    680            }
    681            for (int i = 0; i < lhs.length && isEquals; ++i) {
    682                append(lhs[i], rhs[i]);
    683            }
    684            return this;
    685        }
    686
    687        /**
    688         * <p>Deep comparison of array of <code>int</code>. Length and all
    689         * values are compared.</p>
    690         *
    691         * <p>The method {@link #append(int, int)} is used.</p>
    692         *
    693         * @param lhs  the left hand <code>int[]</code>
    694         * @param rhs  the right hand <code>int[]</code>
    695         * @return EqualsBuilder - used to chain calls.
    696         */
    697        public EqualsBuilder append(int[] lhs, int[] rhs) {
    698            if (isEquals == false) {
    699                return this;
    700            }
    701            if (lhs == rhs) {
    702                return this;
    703            }
    704            if (lhs == null || rhs == null) {
    705                this.setEquals(false);
    706                return this;
    707            }
    708            if (lhs.length != rhs.length) {
    709                this.setEquals(false);
    710                return this;
    711            }
    712            for (int i = 0; i < lhs.length && isEquals; ++i) {
    713                append(lhs[i], rhs[i]);
    714            }
    715            return this;
    716        }
    717
    718        /**
    719         * <p>Deep comparison of array of <code>short</code>. Length and all
    720         * values are compared.</p>
    721         *
    722         * <p>The method {@link #append(short, short)} is used.</p>
    723         *
    724         * @param lhs  the left hand <code>short[]</code>
    725         * @param rhs  the right hand <code>short[]</code>
    726         * @return EqualsBuilder - used to chain calls.
    727         */
    728        public EqualsBuilder append(short[] lhs, short[] rhs) {
    729            if (isEquals == false) {
    730                return this;
    731            }
    732            if (lhs == rhs) {
    733                return this;
    734            }
    735            if (lhs == null || rhs == null) {
    736                this.setEquals(false);
    737                return this;
    738            }
    739            if (lhs.length != rhs.length) {
    740                this.setEquals(false);
    741                return this;
    742            }
    743            for (int i = 0; i < lhs.length && isEquals; ++i) {
    744                append(lhs[i], rhs[i]);
    745            }
    746            return this;
    747        }
    748
    749        /**
    750         * <p>Deep comparison of array of <code>char</code>. Length and all
    751         * values are compared.</p>
    752         *
    753         * <p>The method {@link #append(char, char)} is used.</p>
    754         *
    755         * @param lhs  the left hand <code>char[]</code>
    756         * @param rhs  the right hand <code>char[]</code>
    757         * @return EqualsBuilder - used to chain calls.
    758         */
    759        public EqualsBuilder append(char[] lhs, char[] rhs) {
    760            if (isEquals == false) {
    761                return this;
    762            }
    763            if (lhs == rhs) {
    764                return this;
    765            }
    766            if (lhs == null || rhs == null) {
    767                this.setEquals(false);
    768                return this;
    769            }
    770            if (lhs.length != rhs.length) {
    771                this.setEquals(false);
    772                return this;
    773            }
    774            for (int i = 0; i < lhs.length && isEquals; ++i) {
    775                append(lhs[i], rhs[i]);
    776            }
    777            return this;
    778        }
    779
    780        /**
    781         * <p>Deep comparison of array of <code>byte</code>. Length and all
    782         * values are compared.</p>
    783         *
    784         * <p>The method {@link #append(byte, byte)} is used.</p>
    785         *
    786         * @param lhs  the left hand <code>byte[]</code>
    787         * @param rhs  the right hand <code>byte[]</code>
    788         * @return EqualsBuilder - used to chain calls.
    789         */
    790        public EqualsBuilder append(byte[] lhs, byte[] rhs) {
    791            if (isEquals == false) {
    792                return this;
    793            }
    794            if (lhs == rhs) {
    795                return this;
    796            }
    797            if (lhs == null || rhs == null) {
    798                this.setEquals(false);
    799                return this;
    800            }
    801            if (lhs.length != rhs.length) {
    802                this.setEquals(false);
    803                return this;
    804            }
    805            for (int i = 0; i < lhs.length && isEquals; ++i) {
    806                append(lhs[i], rhs[i]);
    807            }
    808            return this;
    809        }
    810
    811        /**
    812         * <p>Deep comparison of array of <code>double</code>. Length and all
    813         * values are compared.</p>
    814         *
    815         * <p>The method {@link #append(double, double)} is used.</p>
    816         *
    817         * @param lhs  the left hand <code>double[]</code>
    818         * @param rhs  the right hand <code>double[]</code>
    819         * @return EqualsBuilder - used to chain calls.
    820         */
    821        public EqualsBuilder append(double[] lhs, double[] rhs) {
    822            if (isEquals == false) {
    823                return this;
    824            }
    825            if (lhs == rhs) {
    826                return this;
    827            }
    828            if (lhs == null || rhs == null) {
    829                this.setEquals(false);
    830                return this;
    831            }
    832            if (lhs.length != rhs.length) {
    833                this.setEquals(false);
    834                return this;
    835            }
    836            for (int i = 0; i < lhs.length && isEquals; ++i) {
    837                append(lhs[i], rhs[i]);
    838            }
    839            return this;
    840        }
    841
    842        /**
    843         * <p>Deep comparison of array of <code>float</code>. Length and all
    844         * values are compared.</p>
    845         *
    846         * <p>The method {@link #append(float, float)} is used.</p>
    847         *
    848         * @param lhs  the left hand <code>float[]</code>
    849         * @param rhs  the right hand <code>float[]</code>
    850         * @return EqualsBuilder - used to chain calls.
    851         */
    852        public EqualsBuilder append(float[] lhs, float[] rhs) {
    853            if (isEquals == false) {
    854                return this;
    855            }
    856            if (lhs == rhs) {
    857                return this;
    858            }
    859            if (lhs == null || rhs == null) {
    860                this.setEquals(false);
    861                return this;
    862            }
    863            if (lhs.length != rhs.length) {
    864                this.setEquals(false);
    865                return this;
    866            }
    867            for (int i = 0; i < lhs.length && isEquals; ++i) {
    868                append(lhs[i], rhs[i]);
    869            }
    870            return this;
    871        }
    872
    873        /**
    874         * <p>Deep comparison of array of <code>boolean</code>. Length and all
    875         * values are compared.</p>
    876         *
    877         * <p>The method {@link #append(boolean, boolean)} is used.</p>
    878         *
    879         * @param lhs  the left hand <code>boolean[]</code>
    880         * @param rhs  the right hand <code>boolean[]</code>
    881         * @return EqualsBuilder - used to chain calls.
    882         */
    883        public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
    884            if (isEquals == false) {
    885                return this;
    886            }
    887            if (lhs == rhs) {
    888                return this;
    889            }
    890            if (lhs == null || rhs == null) {
    891                this.setEquals(false);
    892                return this;
    893            }
    894            if (lhs.length != rhs.length) {
    895                this.setEquals(false);
    896                return this;
    897            }
    898            for (int i = 0; i < lhs.length && isEquals; ++i) {
    899                append(lhs[i], rhs[i]);
    900            }
    901            return this;
    902        }
    903
    904        /**
    905         * <p>Returns <code>true</code> if the fields that have been checked
    906         * are all equal.</p>
    907         *
    908         * @return boolean
    909         */
    910        public boolean isEquals() {
    911            return this.isEquals;
    912        }
    913
    914        /**
    915         * <p>Returns <code>true</code> if the fields that have been checked
    916         * are all equal.</p>
    917         *
    918         * @return <code>true</code> if all of the fields that have been checked
    919         *         are equal, <code>false</code> otherwise.
    920         *
    921         * @since 3.0
    922         */
    923        public Boolean build() {
    924            return Boolean.valueOf(isEquals());
    925        }
    926
    927        /**
    928         * Sets the <code>isEquals</code> value.
    929         *
    930         * @param isEquals The value to set.
    931         * @since 2.1
    932         */
    933        protected void setEquals(boolean isEquals) {
    934            this.isEquals = isEquals;
    935        }
    936
    937        /**
    938         * Reset the EqualsBuilder so you can use the same object again
    939         * @since 2.5
    940         */
    941        public void reset() {
    942            this.isEquals = true;
    943        }
    944    }