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 */
017package org.apache.commons.lang3.builder;
018
019import java.lang.reflect.AccessibleObject;
020import java.lang.reflect.Field;
021import java.lang.reflect.Modifier;
022import java.util.ArrayList;
023import java.util.Collection;
024import java.util.HashSet;
025import java.util.List;
026import java.util.Set;
027
028import org.apache.commons.lang3.ArrayUtils;
029import org.apache.commons.lang3.ClassUtils;
030import org.apache.commons.lang3.tuple.Pair;
031
032/**
033 * Assists in implementing {@link Object#equals(Object)} methods.
034 *
035 * <p> This class provides methods to build a good equals method for any
036 * class. It follows rules laid out in
037 * <a href="https://www.oracle.com/java/technologies/effectivejava.html">Effective Java</a>
038 * , by Joshua Bloch. In particular the rule for comparing {@code doubles},
039 * {@code floats}, and arrays can be tricky. Also, making sure that
040 * {@code equals()} and {@code hashCode()} are consistent can be
041 * difficult.</p>
042 *
043 * <p>Two Objects that compare as equals must generate the same hash code,
044 * but two Objects with the same hash code do not have to be equal.</p>
045 *
046 * <p>All relevant fields should be included in the calculation of equals.
047 * Derived fields may be ignored. In particular, any field used in
048 * generating a hash code must be used in the equals method, and vice
049 * versa.</p>
050 *
051 * <p>Typical use for the code is as follows:</p>
052 * <pre>
053 * public boolean equals(Object obj) {
054 *   if (obj == null) { return false; }
055 *   if (obj == this) { return true; }
056 *   if (obj.getClass() != getClass()) {
057 *     return false;
058 *   }
059 *   MyClass rhs = (MyClass) obj;
060 *   return new EqualsBuilder()
061 *                 .appendSuper(super.equals(obj))
062 *                 .append(field1, rhs.field1)
063 *                 .append(field2, rhs.field2)
064 *                 .append(field3, rhs.field3)
065 *                 .isEquals();
066 *  }
067 * </pre>
068 *
069 * <p> Alternatively, there is a method that uses reflection to determine
070 * the fields to test. Because these fields are usually private, the method,
071 * {@code reflectionEquals}, uses {@code AccessibleObject.setAccessible} to
072 * change the visibility of the fields. This will fail under a security
073 * manager, unless the appropriate permissions are set up correctly. It is
074 * also slower than testing explicitly.  Non-primitive fields are compared using
075 * {@code equals()}.</p>
076 *
077 * <p> A typical invocation for this method would look like:</p>
078 * <pre>
079 * public boolean equals(Object obj) {
080 *   return EqualsBuilder.reflectionEquals(this, obj);
081 * }
082 * </pre>
083 *
084 * <p>The {@link EqualsExclude} annotation can be used to exclude fields from being
085 * used by the {@code reflectionEquals} methods.</p>
086 *
087 * @since 1.0
088 */
089public class EqualsBuilder implements Builder<Boolean> {
090
091    /**
092     * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
093     *
094     * @since 3.0
095     */
096    private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<>();
097
098    /*
099     * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
100     * we are in the process of calculating.
101     *
102     * So we generate a one-to-one mapping from the original object to a new object.
103     *
104     * Now HashSet uses equals() to determine if two elements with the same hash code really
105     * are equal, so we also need to ensure that the replacement objects are only equal
106     * if the original objects are identical.
107     *
108     * The original implementation (2.4 and before) used the System.identityHashCode()
109     * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
110     *
111     * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
112     * to disambiguate the duplicate ids.
113     */
114
115    /**
116     * Converters value pair into a register pair.
117     *
118     * @param lhs {@code this} object
119     * @param rhs the other object
120     *
121     * @return the pair
122     */
123    static Pair<IDKey, IDKey> getRegisterPair(final Object lhs, final Object rhs) {
124        final IDKey left = new IDKey(lhs);
125        final IDKey right = new IDKey(rhs);
126        return Pair.of(left, right);
127    }
128
129    /**
130     * Returns the registry of object pairs being traversed by the reflection
131     * methods in the current thread.
132     *
133     * @return Set the registry of objects being traversed
134     * @since 3.0
135     */
136    static Set<Pair<IDKey, IDKey>> getRegistry() {
137        return REGISTRY.get();
138    }
139
140    /**
141     * Returns {@code true} if the registry contains the given object pair.
142     * Used by the reflection methods to avoid infinite loops.
143     * Objects might be swapped therefore a check is needed if the object pair
144     * is registered in given or swapped order.
145     *
146     * @param lhs {@code this} object to lookup in registry
147     * @param rhs the other object to lookup on registry
148     * @return boolean {@code true} if the registry contains the given object.
149     * @since 3.0
150     */
151    static boolean isRegistered(final Object lhs, final Object rhs) {
152        final Set<Pair<IDKey, IDKey>> registry = getRegistry();
153        final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
154        final Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getRight(), pair.getLeft());
155
156        return registry != null
157                && (registry.contains(pair) || registry.contains(swappedPair));
158    }
159
160    /**
161     * This method uses reflection to determine if the two {@link Object}s
162     * are equal.
163     *
164     * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private
165     * fields. This means that it will throw a security exception if run under
166     * a security manager, if the permissions are not set up correctly. It is also
167     * not as efficient as testing explicitly. Non-primitive fields are compared using
168     * {@code equals()}.</p>
169     *
170     * <p>If the TestTransients parameter is set to {@code true}, transient
171     * members will be tested, otherwise they are ignored, as they are likely
172     * derived fields, and not part of the value of the {@link Object}.</p>
173     *
174     * <p>Static fields will not be tested. Superclass fields will be included.</p>
175     *
176     * @param lhs  {@code this} object
177     * @param rhs  the other object
178     * @param testTransients  whether to include transient fields
179     * @return {@code true} if the two Objects have tested equals.
180     *
181     * @see EqualsExclude
182     */
183    public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients) {
184        return reflectionEquals(lhs, rhs, testTransients, null);
185    }
186
187    /**
188     * This method uses reflection to determine if the two {@link Object}s
189     * are equal.
190     *
191     * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private
192     * fields. This means that it will throw a security exception if run under
193     * a security manager, if the permissions are not set up correctly. It is also
194     * not as efficient as testing explicitly. Non-primitive fields are compared using
195     * {@code equals()}.</p>
196     *
197     * <p>If the testTransients parameter is set to {@code true}, transient
198     * members will be tested, otherwise they are ignored, as they are likely
199     * derived fields, and not part of the value of the {@link Object}.</p>
200     *
201     * <p>Static fields will not be included. Superclass fields will be appended
202     * up to and including the specified superclass. A null superclass is treated
203     * as java.lang.Object.</p>
204     *
205     * <p>If the testRecursive parameter is set to {@code true}, non primitive
206     * (and non primitive wrapper) field types will be compared by
207     * {@link EqualsBuilder} recursively instead of invoking their
208     * {@code equals()} method. Leading to a deep reflection equals test.
209     *
210     * @param lhs  {@code this} object
211     * @param rhs  the other object
212     * @param testTransients  whether to include transient fields
213     * @param reflectUpToClass  the superclass to reflect up to (inclusive),
214     *  may be {@code null}
215     * @param testRecursive  whether to call reflection equals on non-primitive
216     *  fields recursively.
217     * @param excludeFields  array of field names to exclude from testing
218     * @return {@code true} if the two Objects have tested equals.
219     *
220     * @see EqualsExclude
221     * @since 3.6
222     */
223    public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass,
224            final boolean testRecursive, final String... excludeFields) {
225        if (lhs == rhs) {
226            return true;
227        }
228        if (lhs == null || rhs == null) {
229            return false;
230        }
231        return new EqualsBuilder()
232                    .setExcludeFields(excludeFields)
233                    .setReflectUpToClass(reflectUpToClass)
234                    .setTestTransients(testTransients)
235                    .setTestRecursive(testRecursive)
236                    .reflectionAppend(lhs, rhs)
237                    .isEquals();
238    }
239
240    /**
241     * This method uses reflection to determine if the two {@link Object}s
242     * are equal.
243     *
244     * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private
245     * fields. This means that it will throw a security exception if run under
246     * a security manager, if the permissions are not set up correctly. It is also
247     * not as efficient as testing explicitly. Non-primitive fields are compared using
248     * {@code equals()}.</p>
249     *
250     * <p>If the testTransients parameter is set to {@code true}, transient
251     * members will be tested, otherwise they are ignored, as they are likely
252     * derived fields, and not part of the value of the {@link Object}.</p>
253     *
254     * <p>Static fields will not be included. Superclass fields will be appended
255     * up to and including the specified superclass. A null superclass is treated
256     * as java.lang.Object.</p>
257     *
258     * @param lhs  {@code this} object
259     * @param rhs  the other object
260     * @param testTransients  whether to include transient fields
261     * @param reflectUpToClass  the superclass to reflect up to (inclusive),
262     *  may be {@code null}
263     * @param excludeFields  array of field names to exclude from testing
264     * @return {@code true} if the two Objects have tested equals.
265     *
266     * @see EqualsExclude
267     * @since 2.0
268     */
269    public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass,
270            final String... excludeFields) {
271        return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, false, excludeFields);
272    }
273
274    /**
275     * This method uses reflection to determine if the two {@link Object}s
276     * are equal.
277     *
278     * <p>It uses {@code AccessibleObject.setAccessible} 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. Non-primitive fields are compared using
282     * {@code equals()}.</p>
283     *
284     * <p>Transient members will be not be tested, as they are likely derived
285     * fields, and not part of the value of the Object.</p>
286     *
287     * <p>Static fields will not be tested. Superclass fields will be included.</p>
288     *
289     * @param lhs  {@code this} object
290     * @param rhs  the other object
291     * @param excludeFields  Collection of String field names to exclude from testing
292     * @return {@code true} if the two Objects have tested equals.
293     *
294     * @see EqualsExclude
295     */
296    public static boolean reflectionEquals(final Object lhs, final Object rhs, final Collection<String> excludeFields) {
297        return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
298    }
299    /**
300     * This method uses reflection to determine if the two {@link Object}s
301     * are equal.
302     *
303     * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private
304     * fields. This means that it will throw a security exception if run under
305     * a security manager, if the permissions are not set up correctly. It is also
306     * not as efficient as testing explicitly. Non-primitive fields are compared using
307     * {@code equals()}.</p>
308     *
309     * <p>Transient members will be not be tested, as they are likely derived
310     * fields, and not part of the value of the Object.</p>
311     *
312     * <p>Static fields will not be tested. Superclass fields will be included.</p>
313     *
314     * @param lhs  {@code this} object
315     * @param rhs  the other object
316     * @param excludeFields  array of field names to exclude from testing
317     * @return {@code true} if the two Objects have tested equals.
318     *
319     * @see EqualsExclude
320     */
321    public static boolean reflectionEquals(final Object lhs, final Object rhs, final String... excludeFields) {
322        return reflectionEquals(lhs, rhs, false, null, excludeFields);
323    }
324    /**
325     * Registers the given object pair.
326     * Used by the reflection methods to avoid infinite loops.
327     *
328     * @param lhs {@code this} object to register
329     * @param rhs the other object to register
330     */
331    private static void register(final Object lhs, final Object rhs) {
332        Set<Pair<IDKey, IDKey>> registry = getRegistry();
333        if (registry == null) {
334            registry = new HashSet<>();
335            REGISTRY.set(registry);
336        }
337        final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
338        registry.add(pair);
339    }
340    /**
341     * Unregisters the given object pair.
342     *
343     * <p>
344     * Used by the reflection methods to avoid infinite loops.
345     *
346     * @param lhs {@code this} object to unregister
347     * @param rhs the other object to unregister
348     * @since 3.0
349     */
350    private static void unregister(final Object lhs, final Object rhs) {
351        final Set<Pair<IDKey, IDKey>> registry = getRegistry();
352        if (registry != null) {
353            registry.remove(getRegisterPair(lhs, rhs));
354            if (registry.isEmpty()) {
355                REGISTRY.remove();
356            }
357        }
358    }
359    /**
360     * If the fields tested are equals.
361     * The default value is {@code true}.
362     */
363    private boolean isEquals = true;
364
365    private boolean testTransients;
366
367    private boolean testRecursive;
368
369    private List<Class<?>> bypassReflectionClasses;
370
371    private Class<?> reflectUpToClass;
372
373    private String[] excludeFields;
374
375    /**
376     * Constructor for EqualsBuilder.
377     *
378     * <p>Starts off assuming that equals is {@code true}.</p>
379     * @see Object#equals(Object)
380     */
381    public EqualsBuilder() {
382        // set up default classes to bypass reflection for
383        bypassReflectionClasses = new ArrayList<>(1);
384        bypassReflectionClasses.add(String.class); //hashCode field being lazy but not transient
385    }
386
387
388    /**
389     * Test if two {@code booleans}s are equal.
390     *
391     * @param lhs  the left-hand {@code boolean}
392     * @param rhs  the right-hand {@code boolean}
393     * @return this
394      */
395    public EqualsBuilder append(final boolean lhs, final boolean rhs) {
396        if (!isEquals) {
397            return this;
398        }
399        isEquals = lhs == rhs;
400        return this;
401    }
402
403    /**
404     * Deep comparison of array of {@code boolean}. Length and all
405     * values are compared.
406     *
407     * <p>The method {@link #append(boolean, boolean)} is used.</p>
408     *
409     * @param lhs  the left-hand {@code boolean[]}
410     * @param rhs  the right-hand {@code boolean[]}
411     * @return this
412     */
413    public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) {
414        if (!isEquals) {
415            return this;
416        }
417        if (lhs == rhs) {
418            return this;
419        }
420        if (lhs == null || rhs == null) {
421            this.setEquals(false);
422            return this;
423        }
424        if (lhs.length != rhs.length) {
425            this.setEquals(false);
426            return this;
427        }
428        for (int i = 0; i < lhs.length && isEquals; ++i) {
429            append(lhs[i], rhs[i]);
430        }
431        return this;
432    }
433
434    /**
435     * Test if two {@code byte}s are equal.
436     *
437     * @param lhs  the left-hand {@code byte}
438     * @param rhs  the right-hand {@code byte}
439     * @return this
440     */
441    public EqualsBuilder append(final byte lhs, final byte rhs) {
442        if (!isEquals) {
443            return this;
444        }
445        isEquals = lhs == rhs;
446        return this;
447    }
448
449    /**
450     * Deep comparison of array of {@code byte}. Length and all
451     * values are compared.
452     *
453     * <p>The method {@link #append(byte, byte)} is used.</p>
454     *
455     * @param lhs  the left-hand {@code byte[]}
456     * @param rhs  the right-hand {@code byte[]}
457     * @return this
458     */
459    public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
460        if (!isEquals) {
461            return this;
462        }
463        if (lhs == rhs) {
464            return this;
465        }
466        if (lhs == null || rhs == null) {
467            this.setEquals(false);
468            return this;
469        }
470        if (lhs.length != rhs.length) {
471            this.setEquals(false);
472            return this;
473        }
474        for (int i = 0; i < lhs.length && isEquals; ++i) {
475            append(lhs[i], rhs[i]);
476        }
477        return this;
478    }
479
480    /**
481     * Test if two {@code char}s are equal.
482     *
483     * @param lhs  the left-hand {@code char}
484     * @param rhs  the right-hand {@code char}
485     * @return this
486     */
487    public EqualsBuilder append(final char lhs, final char rhs) {
488        if (!isEquals) {
489            return this;
490        }
491        isEquals = lhs == rhs;
492        return this;
493    }
494
495    /**
496     * Deep comparison of array of {@code char}. Length and all
497     * values are compared.
498     *
499     * <p>The method {@link #append(char, char)} is used.</p>
500     *
501     * @param lhs  the left-hand {@code char[]}
502     * @param rhs  the right-hand {@code char[]}
503     * @return this
504     */
505    public EqualsBuilder append(final char[] lhs, final char[] rhs) {
506        if (!isEquals) {
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        if (lhs.length != rhs.length) {
517            this.setEquals(false);
518            return this;
519        }
520        for (int i = 0; i < lhs.length && isEquals; ++i) {
521            append(lhs[i], rhs[i]);
522        }
523        return this;
524    }
525
526    /**
527     * Test if two {@code double}s are equal by testing that the
528     * pattern of bits returned by {@code doubleToLong} are equal.
529     *
530     * <p>This handles NaNs, Infinities, and {@code -0.0}.</p>
531     *
532     * <p>It is compatible with the hash code generated by
533     * {@link HashCodeBuilder}.</p>
534     *
535     * @param lhs  the left-hand {@code double}
536     * @param rhs  the right-hand {@code double}
537     * @return this
538     */
539    public EqualsBuilder append(final double lhs, final double rhs) {
540        if (!isEquals) {
541            return this;
542        }
543        return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
544    }
545
546    /**
547     * Deep comparison of array of {@code double}. Length and all
548     * values are compared.
549     *
550     * <p>The method {@link #append(double, double)} is used.</p>
551     *
552     * @param lhs  the left-hand {@code double[]}
553     * @param rhs  the right-hand {@code double[]}
554     * @return this
555     */
556    public EqualsBuilder append(final double[] lhs, final double[] rhs) {
557        if (!isEquals) {
558            return this;
559        }
560        if (lhs == rhs) {
561            return this;
562        }
563        if (lhs == null || rhs == null) {
564            this.setEquals(false);
565            return this;
566        }
567        if (lhs.length != rhs.length) {
568            this.setEquals(false);
569            return this;
570        }
571        for (int i = 0; i < lhs.length && isEquals; ++i) {
572            append(lhs[i], rhs[i]);
573        }
574        return this;
575    }
576
577    /**
578     * Test if two {@code float}s are equal by testing that the
579     * pattern of bits returned by doubleToLong are equal.
580     *
581     * <p>This handles NaNs, Infinities, and {@code -0.0}.</p>
582     *
583     * <p>It is compatible with the hash code generated by
584     * {@link HashCodeBuilder}.</p>
585     *
586     * @param lhs  the left-hand {@code float}
587     * @param rhs  the right-hand {@code float}
588     * @return this
589     */
590    public EqualsBuilder append(final float lhs, final float rhs) {
591        if (!isEquals) {
592            return this;
593        }
594        return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
595    }
596
597    /**
598     * Deep comparison of array of {@code float}. Length and all
599     * values are compared.
600     *
601     * <p>The method {@link #append(float, float)} is used.</p>
602     *
603     * @param lhs  the left-hand {@code float[]}
604     * @param rhs  the right-hand {@code float[]}
605     * @return this
606     */
607    public EqualsBuilder append(final float[] lhs, final float[] rhs) {
608        if (!isEquals) {
609            return this;
610        }
611        if (lhs == rhs) {
612            return this;
613        }
614        if (lhs == null || rhs == null) {
615            this.setEquals(false);
616            return this;
617        }
618        if (lhs.length != rhs.length) {
619            this.setEquals(false);
620            return this;
621        }
622        for (int i = 0; i < lhs.length && isEquals; ++i) {
623            append(lhs[i], rhs[i]);
624        }
625        return this;
626    }
627
628    /**
629     * Test if two {@code int}s are equal.
630     *
631     * @param lhs  the left-hand {@code int}
632     * @param rhs  the right-hand {@code int}
633     * @return this
634     */
635    public EqualsBuilder append(final int lhs, final int rhs) {
636        if (!isEquals) {
637            return this;
638        }
639        isEquals = lhs == rhs;
640        return this;
641    }
642
643    /**
644     * Deep comparison of array of {@code int}. Length and all
645     * values are compared.
646     *
647     * <p>The method {@link #append(int, int)} is used.</p>
648     *
649     * @param lhs  the left-hand {@code int[]}
650     * @param rhs  the right-hand {@code int[]}
651     * @return this
652     */
653    public EqualsBuilder append(final int[] lhs, final int[] rhs) {
654        if (!isEquals) {
655            return this;
656        }
657        if (lhs == rhs) {
658            return this;
659        }
660        if (lhs == null || rhs == null) {
661            this.setEquals(false);
662            return this;
663        }
664        if (lhs.length != rhs.length) {
665            this.setEquals(false);
666            return this;
667        }
668        for (int i = 0; i < lhs.length && isEquals; ++i) {
669            append(lhs[i], rhs[i]);
670        }
671        return this;
672    }
673
674    /**
675     * Test if two {@code long} s are equal.
676     *
677     * @param lhs
678     *                  the left-hand {@code long}
679     * @param rhs
680     *                  the right-hand {@code long}
681     * @return this
682     */
683    public EqualsBuilder append(final long lhs, final long rhs) {
684        if (!isEquals) {
685            return this;
686        }
687        isEquals = lhs == rhs;
688        return this;
689    }
690
691    /**
692     * Deep comparison of array of {@code long}. Length and all
693     * values are compared.
694     *
695     * <p>The method {@link #append(long, long)} is used.</p>
696     *
697     * @param lhs  the left-hand {@code long[]}
698     * @param rhs  the right-hand {@code long[]}
699     * @return this
700     */
701    public EqualsBuilder append(final long[] lhs, final long[] rhs) {
702        if (!isEquals) {
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     * Test if two {@link Object}s are equal using either
724     * #{@link #reflectionAppend(Object, Object)}, if object are non
725     * primitives (or wrapper of primitives) or if field {@code testRecursive}
726     * is set to {@code false}. Otherwise, using their
727     * {@code equals} method.
728     *
729     * @param lhs  the left-hand object
730     * @param rhs  the right-hand object
731     * @return this
732     */
733    public EqualsBuilder append(final Object lhs, final Object rhs) {
734        if (!isEquals) {
735            return this;
736        }
737        if (lhs == rhs) {
738            return this;
739        }
740        if (lhs == null || rhs == null) {
741            this.setEquals(false);
742            return this;
743        }
744        final Class<?> lhsClass = lhs.getClass();
745        if (lhsClass.isArray()) {
746            // factor out array case in order to keep method small enough
747            // to be inlined
748            appendArray(lhs, rhs);
749        } else // The simple case, not an array, just test the element
750        if (testRecursive && !ClassUtils.isPrimitiveOrWrapper(lhsClass)) {
751            reflectionAppend(lhs, rhs);
752        } else {
753            isEquals = lhs.equals(rhs);
754        }
755        return this;
756    }
757
758    /**
759     * Performs a deep comparison of two {@link Object} arrays.
760     *
761     * <p>This also will be called for the top level of
762     * multi-dimensional, ragged, and multi-typed arrays.</p>
763     *
764     * <p>Note that this method does not compare the type of the arrays; it only
765     * compares the contents.</p>
766     *
767     * @param lhs  the left-hand {@code Object[]}
768     * @param rhs  the right-hand {@code Object[]}
769     * @return this
770     */
771    public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
772        if (!isEquals) {
773            return this;
774        }
775        if (lhs == rhs) {
776            return this;
777        }
778        if (lhs == null || rhs == null) {
779            this.setEquals(false);
780            return this;
781        }
782        if (lhs.length != rhs.length) {
783            this.setEquals(false);
784            return this;
785        }
786        for (int i = 0; i < lhs.length && isEquals; ++i) {
787            append(lhs[i], rhs[i]);
788        }
789        return this;
790    }
791
792    /**
793     * Test if two {@code short}s are equal.
794     *
795     * @param lhs  the left-hand {@code short}
796     * @param rhs  the right-hand {@code short}
797     * @return this
798     */
799    public EqualsBuilder append(final short lhs, final short rhs) {
800        if (!isEquals) {
801            return this;
802        }
803        isEquals = lhs == rhs;
804        return this;
805    }
806
807    /**
808     * Deep comparison of array of {@code short}. Length and all
809     * values are compared.
810     *
811     * <p>The method {@link #append(short, short)} is used.</p>
812     *
813     * @param lhs  the left-hand {@code short[]}
814     * @param rhs  the right-hand {@code short[]}
815     * @return this
816     */
817    public EqualsBuilder append(final short[] lhs, final short[] rhs) {
818        if (!isEquals) {
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     * Test if an {@link Object} is equal to an array.
840     *
841     * @param lhs  the left-hand object, an array
842     * @param rhs  the right-hand object
843     */
844    private void appendArray(final Object lhs, final Object rhs) {
845        // First we compare different dimensions, for example: a boolean[][] to a boolean[]
846        // then we 'Switch' on type of array, to dispatch to the correct handler
847        // This handles multidimensional arrays of the same depth
848        if (lhs.getClass() != rhs.getClass()) {
849            this.setEquals(false);
850        } else if (lhs instanceof long[]) {
851            append((long[]) lhs, (long[]) rhs);
852        } else if (lhs instanceof int[]) {
853            append((int[]) lhs, (int[]) rhs);
854        } else if (lhs instanceof short[]) {
855            append((short[]) lhs, (short[]) rhs);
856        } else if (lhs instanceof char[]) {
857            append((char[]) lhs, (char[]) rhs);
858        } else if (lhs instanceof byte[]) {
859            append((byte[]) lhs, (byte[]) rhs);
860        } else if (lhs instanceof double[]) {
861            append((double[]) lhs, (double[]) rhs);
862        } else if (lhs instanceof float[]) {
863            append((float[]) lhs, (float[]) rhs);
864        } else if (lhs instanceof boolean[]) {
865            append((boolean[]) lhs, (boolean[]) rhs);
866        } else {
867            // Not an array of primitives
868            append((Object[]) lhs, (Object[]) rhs);
869        }
870    }
871
872    /**
873     * Adds the result of {@code super.equals()} to this builder.
874     *
875     * @param superEquals  the result of calling {@code super.equals()}
876     * @return this
877     * @since 2.0
878     */
879    public EqualsBuilder appendSuper(final boolean superEquals) {
880        if (!isEquals) {
881            return this;
882        }
883        isEquals = superEquals;
884        return this;
885    }
886
887    /**
888     * Returns {@code true} if the fields that have been checked
889     * are all equal.
890     *
891     * @return {@code true} if all of the fields that have been checked
892     *         are equal, {@code false} otherwise.
893     *
894     * @since 3.0
895     */
896    @Override
897    public Boolean build() {
898        return Boolean.valueOf(isEquals());
899    }
900
901    /**
902     * Returns {@code true} if the fields that have been checked
903     * are all equal.
904     *
905     * @return boolean
906     */
907    public boolean isEquals() {
908        return this.isEquals;
909    }
910
911    /**
912     * Tests if two {@code objects} by using reflection.
913     *
914     * <p>It uses {@code AccessibleObject.setAccessible} to gain access to private
915     * fields. This means that it will throw a security exception if run under
916     * a security manager, if the permissions are not set up correctly. It is also
917     * not as efficient as testing explicitly. Non-primitive fields are compared using
918     * {@code equals()}.</p>
919     *
920     * <p>If the testTransients field is set to {@code true}, transient
921     * members will be tested, otherwise they are ignored, as they are likely
922     * derived fields, and not part of the value of the {@link Object}.</p>
923     *
924     * <p>Static fields will not be included. Superclass fields will be appended
925     * up to and including the specified superclass in field {@code reflectUpToClass}.
926     * A null superclass is treated as java.lang.Object.</p>
927     *
928     * <p>Field names listed in field {@code excludeFields} will be ignored.</p>
929     *
930     * <p>If either class of the compared objects is contained in
931     * {@code bypassReflectionClasses}, both objects are compared by calling
932     * the equals method of the left-hand object with the right-hand object as an argument.</p>
933     *
934     * @param lhs  the left-hand object
935     * @param rhs  the right-hand object
936     * @return this
937     */
938    public EqualsBuilder reflectionAppend(final Object lhs, final Object rhs) {
939        if (!isEquals) {
940            return this;
941        }
942        if (lhs == rhs) {
943            return this;
944        }
945        if (lhs == null || rhs == null) {
946            isEquals = false;
947            return this;
948        }
949
950        // Find the leaf class since there may be transients in the leaf
951        // class or in classes between the leaf and root.
952        // If we are not testing transients or a subclass has no ivars,
953        // then a subclass can test equals to a superclass.
954        final Class<?> lhsClass = lhs.getClass();
955        final Class<?> rhsClass = rhs.getClass();
956        Class<?> testClass;
957        if (lhsClass.isInstance(rhs)) {
958            testClass = lhsClass;
959            if (!rhsClass.isInstance(lhs)) {
960                // rhsClass is a subclass of lhsClass
961                testClass = rhsClass;
962            }
963        } else if (rhsClass.isInstance(lhs)) {
964            testClass = rhsClass;
965            if (!lhsClass.isInstance(rhs)) {
966                // lhsClass is a subclass of rhsClass
967                testClass = lhsClass;
968            }
969        } else {
970            // The two classes are not related.
971            isEquals = false;
972            return this;
973        }
974
975        try {
976            if (testClass.isArray()) {
977                append(lhs, rhs);
978            } else //If either class is being excluded, call normal object equals method on lhsClass.
979            if (bypassReflectionClasses != null
980                    && (bypassReflectionClasses.contains(lhsClass) || bypassReflectionClasses.contains(rhsClass))) {
981                isEquals = lhs.equals(rhs);
982            } else {
983                reflectionAppend(lhs, rhs, testClass);
984                while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
985                    testClass = testClass.getSuperclass();
986                    reflectionAppend(lhs, rhs, testClass);
987                }
988            }
989        } catch (final IllegalArgumentException e) {
990            // In this case, we tried to test a subclass vs. a superclass and
991            // the subclass has ivars or the ivars are transient and
992            // we are testing transients.
993            // If a subclass has ivars that we are trying to test them, we get an
994            // exception and we know that the objects are not equal.
995            isEquals = false;
996        }
997        return this;
998    }
999
1000    /**
1001     * Appends the fields and values defined by the given object of the
1002     * given Class.
1003     *
1004     * @param lhs  the left-hand object
1005     * @param rhs  the right-hand object
1006     * @param clazz  the class to append details of
1007     */
1008    private void reflectionAppend(
1009        final Object lhs,
1010        final Object rhs,
1011        final Class<?> clazz) {
1012
1013        if (isRegistered(lhs, rhs)) {
1014            return;
1015        }
1016
1017        try {
1018            register(lhs, rhs);
1019            final Field[] fields = clazz.getDeclaredFields();
1020            AccessibleObject.setAccessible(fields, true);
1021            for (int i = 0; i < fields.length && isEquals; i++) {
1022                final Field field = fields[i];
1023                if (!ArrayUtils.contains(excludeFields, field.getName())
1024                    && !field.getName().contains("$")
1025                    && (testTransients || !Modifier.isTransient(field.getModifiers()))
1026                    && !Modifier.isStatic(field.getModifiers())
1027                    && !field.isAnnotationPresent(EqualsExclude.class)) {
1028                    append(Reflection.getUnchecked(field, lhs), Reflection.getUnchecked(field, rhs));
1029                }
1030            }
1031        } finally {
1032            unregister(lhs, rhs);
1033        }
1034    }
1035
1036    /**
1037     * Reset the EqualsBuilder so you can use the same object again
1038     * @since 2.5
1039     */
1040    public void reset() {
1041        this.isEquals = true;
1042    }
1043
1044    /**
1045     * Sets {@link Class}es whose instances should be compared by calling their {@code equals}
1046     * although being in recursive mode. So the fields of theses classes will not be compared recursively by reflection.
1047     *
1048     * <p>Here you should name classes having non-transient fields which are cache fields being set lazily.<br>
1049     * Prominent example being {@link String} class with its hash code cache field. Due to the importance
1050     * of the {@link String} class, it is included in the default bypasses classes. Usually, if you use
1051     * your own set of classes here, remember to include {@link String} class, too.</p>
1052     * @param bypassReflectionClasses  classes to bypass reflection test
1053     * @return this
1054     * @see #setTestRecursive(boolean)
1055     * @since 3.8
1056     */
1057    public EqualsBuilder setBypassReflectionClasses(final List<Class<?>> bypassReflectionClasses) {
1058        this.bypassReflectionClasses = bypassReflectionClasses;
1059        return this;
1060    }
1061
1062    /**
1063     * Sets the {@code isEquals} value.
1064     *
1065     * @param isEquals The value to set.
1066     * @since 2.1
1067     */
1068    protected void setEquals(final boolean isEquals) {
1069        this.isEquals = isEquals;
1070    }
1071
1072    /**
1073     * Sets field names to be excluded by reflection tests.
1074     * @param excludeFields the fields to exclude
1075     * @return this
1076     * @since 3.6
1077     */
1078    public EqualsBuilder setExcludeFields(final String... excludeFields) {
1079        this.excludeFields = excludeFields;
1080        return this;
1081    }
1082
1083    /**
1084     * Sets the superclass to reflect up to at reflective tests.
1085     * @param reflectUpToClass the super class to reflect up to
1086     * @return this
1087     * @since 3.6
1088     */
1089    public EqualsBuilder setReflectUpToClass(final Class<?> reflectUpToClass) {
1090        this.reflectUpToClass = reflectUpToClass;
1091        return this;
1092    }
1093
1094    /**
1095     * Sets whether to test fields recursively, instead of using their equals method, when reflectively comparing objects.
1096     * String objects, which cache a hash value, are automatically excluded from recursive testing.
1097     * You may specify other exceptions by calling {@link #setBypassReflectionClasses(List)}.
1098     * @param testRecursive whether to do a recursive test
1099     * @return this
1100     * @see #setBypassReflectionClasses(List)
1101     * @since 3.6
1102     */
1103    public EqualsBuilder setTestRecursive(final boolean testRecursive) {
1104        this.testRecursive = testRecursive;
1105        return this;
1106    }
1107
1108    /**
1109     * Sets whether to include transient fields when reflectively comparing objects.
1110     * @param testTransients whether to test transient fields
1111     * @return this
1112     * @since 3.6
1113     */
1114    public EqualsBuilder setTestTransients(final boolean testTransients) {
1115        this.testTransients = testTransients;
1116        return this;
1117    }
1118}