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