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