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