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