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