001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.builder;
018
019import java.lang.reflect.AccessibleObject;
020import java.lang.reflect.Field;
021import java.lang.reflect.Modifier;
022import java.util.Collection;
023import java.util.HashSet;
024import java.util.Set;
025
026import org.apache.commons.lang3.ArrayUtils;
027import 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://www.oracle.com/technetwork/java/effectivejava-136174.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 1535757 2013-10-25 15:07:13Z mbenson $
082 */
083public 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(final Object lhs, final Object rhs) {
135        final IDKey left = new IDKey(lhs);
136        final 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(final Object lhs, final Object rhs) {
154        final Set<Pair<IDKey, IDKey>> registry = getRegistry();
155        final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
156        final 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(final Object lhs, final Object rhs) {
172        synchronized (EqualsBuilder.class) {
173            if (getRegistry() == null) {
174                REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>());
175            }
176        }
177
178        final Set<Pair<IDKey, IDKey>> registry = getRegistry();
179        final 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(final Object lhs, final Object rhs) {
196        Set<Pair<IDKey, IDKey>> registry = getRegistry();
197        if (registry != null) {
198            final 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(final Object lhs, final Object rhs, final 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(final Object lhs, final Object rhs, final 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(final Object lhs, final Object rhs, final 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(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass,
325            final 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        final Class<?> lhsClass = lhs.getClass();
337        final 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        final EqualsBuilder equalsBuilder = new EqualsBuilder();
356        try {
357            if (testClass.isArray()) {
358                equalsBuilder.append(lhs, rhs);
359            } else {
360                reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
361                while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
362                    testClass = testClass.getSuperclass();
363                    reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
364                }
365            }
366        } catch (final IllegalArgumentException e) {
367            // In this case, we tried to test a subclass vs. a superclass and
368            // the subclass has ivars or the ivars are transient and
369            // we are testing transients.
370            // If a subclass has ivars that we are trying to test them, we get an
371            // exception and we know that the objects are not equal.
372            return false;
373        }
374        return equalsBuilder.isEquals();
375    }
376
377    /**
378     * <p>Appends the fields and values defined by the given object of the
379     * given Class.</p>
380     *
381     * @param lhs  the left hand object
382     * @param rhs  the right hand object
383     * @param clazz  the class to append details of
384     * @param builder  the builder to append to
385     * @param useTransients  whether to test transient fields
386     * @param excludeFields  array of field names to exclude from testing
387     */
388    private static void reflectionAppend(
389        final Object lhs,
390        final Object rhs,
391        final Class<?> clazz,
392        final EqualsBuilder builder,
393        final boolean useTransients,
394        final String[] excludeFields) {
395
396        if (isRegistered(lhs, rhs)) {
397            return;
398        }
399
400        try {
401            register(lhs, rhs);
402            final Field[] fields = clazz.getDeclaredFields();
403            AccessibleObject.setAccessible(fields, true);
404            for (int i = 0; i < fields.length && builder.isEquals; i++) {
405                final Field f = fields[i];
406                if (!ArrayUtils.contains(excludeFields, f.getName())
407                    && (f.getName().indexOf('$') == -1)
408                    && (useTransients || !Modifier.isTransient(f.getModifiers()))
409                    && (!Modifier.isStatic(f.getModifiers()))) {
410                    try {
411                        builder.append(f.get(lhs), f.get(rhs));
412                    } catch (final IllegalAccessException e) {
413                        //this can't happen. Would get a Security exception instead
414                        //throw a runtime exception in case the impossible happens.
415                        throw new InternalError("Unexpected IllegalAccessException");
416                    }
417                }
418            }
419        } finally {
420            unregister(lhs, rhs);
421        }
422    }
423
424    //-------------------------------------------------------------------------
425
426    /**
427     * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
428     *
429     * @param superEquals  the result of calling <code>super.equals()</code>
430     * @return EqualsBuilder - used to chain calls.
431     * @since 2.0
432     */
433    public EqualsBuilder appendSuper(final boolean superEquals) {
434        if (isEquals == false) {
435            return this;
436        }
437        isEquals = superEquals;
438        return this;
439    }
440
441    //-------------------------------------------------------------------------
442
443    /**
444     * <p>Test if two <code>Object</code>s are equal using their
445     * <code>equals</code> method.</p>
446     *
447     * @param lhs  the left hand object
448     * @param rhs  the right hand object
449     * @return EqualsBuilder - used to chain calls.
450     */
451    public EqualsBuilder append(final Object lhs, final Object rhs) {
452        if (isEquals == false) {
453            return this;
454        }
455        if (lhs == rhs) {
456            return this;
457        }
458        if (lhs == null || rhs == null) {
459            this.setEquals(false);
460            return this;
461        }
462        final Class<?> lhsClass = lhs.getClass();
463        if (!lhsClass.isArray()) {
464            // The simple case, not an array, just test the element
465            isEquals = lhs.equals(rhs);
466        } else if (lhs.getClass() != rhs.getClass()) {
467            // Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
468            this.setEquals(false);
469        }
470        // 'Switch' on type of array, to dispatch to the correct handler
471        // This handles multi dimensional arrays of the same depth
472        else if (lhs instanceof long[]) {
473            append((long[]) lhs, (long[]) rhs);
474        } else if (lhs instanceof int[]) {
475            append((int[]) lhs, (int[]) rhs);
476        } else if (lhs instanceof short[]) {
477            append((short[]) lhs, (short[]) rhs);
478        } else if (lhs instanceof char[]) {
479            append((char[]) lhs, (char[]) rhs);
480        } else if (lhs instanceof byte[]) {
481            append((byte[]) lhs, (byte[]) rhs);
482        } else if (lhs instanceof double[]) {
483            append((double[]) lhs, (double[]) rhs);
484        } else if (lhs instanceof float[]) {
485            append((float[]) lhs, (float[]) rhs);
486        } else if (lhs instanceof boolean[]) {
487            append((boolean[]) lhs, (boolean[]) rhs);
488        } else {
489            // Not an array of primitives
490            append((Object[]) lhs, (Object[]) rhs);
491        }
492        return this;
493    }
494
495    /**
496     * <p>
497     * Test if two <code>long</code> s are equal.
498     * </p>
499     *
500     * @param lhs
501     *                  the left hand <code>long</code>
502     * @param rhs
503     *                  the right hand <code>long</code>
504     * @return EqualsBuilder - used to chain calls.
505     */
506    public EqualsBuilder append(final long lhs, final long rhs) {
507        if (isEquals == false) {
508            return this;
509        }
510        isEquals = (lhs == rhs);
511        return this;
512    }
513
514    /**
515     * <p>Test if two <code>int</code>s are equal.</p>
516     *
517     * @param lhs  the left hand <code>int</code>
518     * @param rhs  the right hand <code>int</code>
519     * @return EqualsBuilder - used to chain calls.
520     */
521    public EqualsBuilder append(final int lhs, final int rhs) {
522        if (isEquals == false) {
523            return this;
524        }
525        isEquals = (lhs == rhs);
526        return this;
527    }
528
529    /**
530     * <p>Test if two <code>short</code>s are equal.</p>
531     *
532     * @param lhs  the left hand <code>short</code>
533     * @param rhs  the right hand <code>short</code>
534     * @return EqualsBuilder - used to chain calls.
535     */
536    public EqualsBuilder append(final short lhs, final short rhs) {
537        if (isEquals == false) {
538            return this;
539        }
540        isEquals = (lhs == rhs);
541        return this;
542    }
543
544    /**
545     * <p>Test if two <code>char</code>s are equal.</p>
546     *
547     * @param lhs  the left hand <code>char</code>
548     * @param rhs  the right hand <code>char</code>
549     * @return EqualsBuilder - used to chain calls.
550     */
551    public EqualsBuilder append(final char lhs, final char rhs) {
552        if (isEquals == false) {
553            return this;
554        }
555        isEquals = (lhs == rhs);
556        return this;
557    }
558
559    /**
560     * <p>Test if two <code>byte</code>s are equal.</p>
561     *
562     * @param lhs  the left hand <code>byte</code>
563     * @param rhs  the right hand <code>byte</code>
564     * @return EqualsBuilder - used to chain calls.
565     */
566    public EqualsBuilder append(final byte lhs, final byte rhs) {
567        if (isEquals == false) {
568            return this;
569        }
570        isEquals = (lhs == rhs);
571        return this;
572    }
573
574    /**
575     * <p>Test if two <code>double</code>s are equal by testing that the
576     * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
577     *
578     * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
579     *
580     * <p>It is compatible with the hash code generated by
581     * <code>HashCodeBuilder</code>.</p>
582     *
583     * @param lhs  the left hand <code>double</code>
584     * @param rhs  the right hand <code>double</code>
585     * @return EqualsBuilder - used to chain calls.
586     */
587    public EqualsBuilder append(final double lhs, final double rhs) {
588        if (isEquals == false) {
589            return this;
590        }
591        return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
592    }
593
594    /**
595     * <p>Test if two <code>float</code>s are equal byt testing that the
596     * pattern of bits returned by doubleToLong are equal.</p>
597     *
598     * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
599     *
600     * <p>It is compatible with the hash code generated by
601     * <code>HashCodeBuilder</code>.</p>
602     *
603     * @param lhs  the left hand <code>float</code>
604     * @param rhs  the right hand <code>float</code>
605     * @return EqualsBuilder - used to chain calls.
606     */
607    public EqualsBuilder append(final float lhs, final float rhs) {
608        if (isEquals == false) {
609            return this;
610        }
611        return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
612    }
613
614    /**
615     * <p>Test if two <code>booleans</code>s are equal.</p>
616     *
617     * @param lhs  the left hand <code>boolean</code>
618     * @param rhs  the right hand <code>boolean</code>
619     * @return EqualsBuilder - used to chain calls.
620      */
621    public EqualsBuilder append(final boolean lhs, final boolean rhs) {
622        if (isEquals == false) {
623            return this;
624        }
625        isEquals = (lhs == rhs);
626        return this;
627    }
628
629    /**
630     * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
631     *
632     * <p>This also will be called for the top level of
633     * multi-dimensional, ragged, and multi-typed arrays.</p>
634     *
635     * @param lhs  the left hand <code>Object[]</code>
636     * @param rhs  the right hand <code>Object[]</code>
637     * @return EqualsBuilder - used to chain calls.
638     */
639    public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
640        if (isEquals == false) {
641            return this;
642        }
643        if (lhs == rhs) {
644            return this;
645        }
646        if (lhs == null || rhs == null) {
647            this.setEquals(false);
648            return this;
649        }
650        if (lhs.length != rhs.length) {
651            this.setEquals(false);
652            return this;
653        }
654        for (int i = 0; i < lhs.length && isEquals; ++i) {
655            append(lhs[i], rhs[i]);
656        }
657        return this;
658    }
659
660    /**
661     * <p>Deep comparison of array of <code>long</code>. Length and all
662     * values are compared.</p>
663     *
664     * <p>The method {@link #append(long, long)} is used.</p>
665     *
666     * @param lhs  the left hand <code>long[]</code>
667     * @param rhs  the right hand <code>long[]</code>
668     * @return EqualsBuilder - used to chain calls.
669     */
670    public EqualsBuilder append(final long[] lhs, final long[] rhs) {
671        if (isEquals == false) {
672            return this;
673        }
674        if (lhs == rhs) {
675            return this;
676        }
677        if (lhs == null || rhs == null) {
678            this.setEquals(false);
679            return this;
680        }
681        if (lhs.length != rhs.length) {
682            this.setEquals(false);
683            return this;
684        }
685        for (int i = 0; i < lhs.length && isEquals; ++i) {
686            append(lhs[i], rhs[i]);
687        }
688        return this;
689    }
690
691    /**
692     * <p>Deep comparison of array of <code>int</code>. Length and all
693     * values are compared.</p>
694     *
695     * <p>The method {@link #append(int, int)} is used.</p>
696     *
697     * @param lhs  the left hand <code>int[]</code>
698     * @param rhs  the right hand <code>int[]</code>
699     * @return EqualsBuilder - used to chain calls.
700     */
701    public EqualsBuilder append(final int[] lhs, final int[] rhs) {
702        if (isEquals == false) {
703            return this;
704        }
705        if (lhs == rhs) {
706            return this;
707        }
708        if (lhs == null || rhs == null) {
709            this.setEquals(false);
710            return this;
711        }
712        if (lhs.length != rhs.length) {
713            this.setEquals(false);
714            return this;
715        }
716        for (int i = 0; i < lhs.length && isEquals; ++i) {
717            append(lhs[i], rhs[i]);
718        }
719        return this;
720    }
721
722    /**
723     * <p>Deep comparison of array of <code>short</code>. Length and all
724     * values are compared.</p>
725     *
726     * <p>The method {@link #append(short, short)} is used.</p>
727     *
728     * @param lhs  the left hand <code>short[]</code>
729     * @param rhs  the right hand <code>short[]</code>
730     * @return EqualsBuilder - used to chain calls.
731     */
732    public EqualsBuilder append(final short[] lhs, final short[] rhs) {
733        if (isEquals == false) {
734            return this;
735        }
736        if (lhs == rhs) {
737            return this;
738        }
739        if (lhs == null || rhs == null) {
740            this.setEquals(false);
741            return this;
742        }
743        if (lhs.length != rhs.length) {
744            this.setEquals(false);
745            return this;
746        }
747        for (int i = 0; i < lhs.length && isEquals; ++i) {
748            append(lhs[i], rhs[i]);
749        }
750        return this;
751    }
752
753    /**
754     * <p>Deep comparison of array of <code>char</code>. Length and all
755     * values are compared.</p>
756     *
757     * <p>The method {@link #append(char, char)} is used.</p>
758     *
759     * @param lhs  the left hand <code>char[]</code>
760     * @param rhs  the right hand <code>char[]</code>
761     * @return EqualsBuilder - used to chain calls.
762     */
763    public EqualsBuilder append(final char[] lhs, final char[] rhs) {
764        if (isEquals == false) {
765            return this;
766        }
767        if (lhs == rhs) {
768            return this;
769        }
770        if (lhs == null || rhs == null) {
771            this.setEquals(false);
772            return this;
773        }
774        if (lhs.length != rhs.length) {
775            this.setEquals(false);
776            return this;
777        }
778        for (int i = 0; i < lhs.length && isEquals; ++i) {
779            append(lhs[i], rhs[i]);
780        }
781        return this;
782    }
783
784    /**
785     * <p>Deep comparison of array of <code>byte</code>. Length and all
786     * values are compared.</p>
787     *
788     * <p>The method {@link #append(byte, byte)} is used.</p>
789     *
790     * @param lhs  the left hand <code>byte[]</code>
791     * @param rhs  the right hand <code>byte[]</code>
792     * @return EqualsBuilder - used to chain calls.
793     */
794    public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
795        if (isEquals == false) {
796            return this;
797        }
798        if (lhs == rhs) {
799            return this;
800        }
801        if (lhs == null || rhs == null) {
802            this.setEquals(false);
803            return this;
804        }
805        if (lhs.length != rhs.length) {
806            this.setEquals(false);
807            return this;
808        }
809        for (int i = 0; i < lhs.length && isEquals; ++i) {
810            append(lhs[i], rhs[i]);
811        }
812        return this;
813    }
814
815    /**
816     * <p>Deep comparison of array of <code>double</code>. Length and all
817     * values are compared.</p>
818     *
819     * <p>The method {@link #append(double, double)} is used.</p>
820     *
821     * @param lhs  the left hand <code>double[]</code>
822     * @param rhs  the right hand <code>double[]</code>
823     * @return EqualsBuilder - used to chain calls.
824     */
825    public EqualsBuilder append(final double[] lhs, final double[] rhs) {
826        if (isEquals == false) {
827            return this;
828        }
829        if (lhs == rhs) {
830            return this;
831        }
832        if (lhs == null || rhs == null) {
833            this.setEquals(false);
834            return this;
835        }
836        if (lhs.length != rhs.length) {
837            this.setEquals(false);
838            return this;
839        }
840        for (int i = 0; i < lhs.length && isEquals; ++i) {
841            append(lhs[i], rhs[i]);
842        }
843        return this;
844    }
845
846    /**
847     * <p>Deep comparison of array of <code>float</code>. Length and all
848     * values are compared.</p>
849     *
850     * <p>The method {@link #append(float, float)} is used.</p>
851     *
852     * @param lhs  the left hand <code>float[]</code>
853     * @param rhs  the right hand <code>float[]</code>
854     * @return EqualsBuilder - used to chain calls.
855     */
856    public EqualsBuilder append(final float[] lhs, final float[] rhs) {
857        if (isEquals == false) {
858            return this;
859        }
860        if (lhs == rhs) {
861            return this;
862        }
863        if (lhs == null || rhs == null) {
864            this.setEquals(false);
865            return this;
866        }
867        if (lhs.length != rhs.length) {
868            this.setEquals(false);
869            return this;
870        }
871        for (int i = 0; i < lhs.length && isEquals; ++i) {
872            append(lhs[i], rhs[i]);
873        }
874        return this;
875    }
876
877    /**
878     * <p>Deep comparison of array of <code>boolean</code>. Length and all
879     * values are compared.</p>
880     *
881     * <p>The method {@link #append(boolean, boolean)} is used.</p>
882     *
883     * @param lhs  the left hand <code>boolean[]</code>
884     * @param rhs  the right hand <code>boolean[]</code>
885     * @return EqualsBuilder - used to chain calls.
886     */
887    public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) {
888        if (isEquals == false) {
889            return this;
890        }
891        if (lhs == rhs) {
892            return this;
893        }
894        if (lhs == null || rhs == null) {
895            this.setEquals(false);
896            return this;
897        }
898        if (lhs.length != rhs.length) {
899            this.setEquals(false);
900            return this;
901        }
902        for (int i = 0; i < lhs.length && isEquals; ++i) {
903            append(lhs[i], rhs[i]);
904        }
905        return this;
906    }
907
908    /**
909     * <p>Returns <code>true</code> if the fields that have been checked
910     * are all equal.</p>
911     *
912     * @return boolean
913     */
914    public boolean isEquals() {
915        return this.isEquals;
916    }
917
918    /**
919     * <p>Returns <code>true</code> if the fields that have been checked
920     * are all equal.</p>
921     *
922     * @return <code>true</code> if all of the fields that have been checked
923     *         are equal, <code>false</code> otherwise.
924     *
925     * @since 3.0
926     */
927    @Override
928    public Boolean build() {
929        return Boolean.valueOf(isEquals());
930    }
931
932    /**
933     * Sets the <code>isEquals</code> value.
934     *
935     * @param isEquals The value to set.
936     * @since 2.1
937     */
938    protected void setEquals(final boolean isEquals) {
939        this.isEquals = isEquals;
940    }
941
942    /**
943     * Reset the EqualsBuilder so you can use the same object again
944     * @since 2.5
945     */
946    public void reset() {
947        this.isEquals = true;
948    }
949}