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