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.Collection;
022import java.util.Comparator;
023import java.util.HashSet;
024import java.util.Objects;
025import java.util.Set;
026
027import org.apache.commons.lang3.ArrayUtils;
028import org.apache.commons.lang3.ObjectUtils;
029import org.apache.commons.lang3.tuple.Pair;
030
031/**
032 * Assists in implementing {@link Comparable#compareTo(Object)} methods.
033 *
034 * <p>
035 * It is consistent with {@code equals(Object)} and
036 * {@code hashCode()} built with {@link EqualsBuilder} and
037 * {@link HashCodeBuilder}.
038 * </p>
039 *
040 * <p>
041 * Two Objects that compare equal using {@code equals(Object)} should normally
042 * also compare equal using {@code compareTo(Object)}.
043 * </p>
044 *
045 * <p>
046 * All relevant fields should be included in the calculation of the
047 * comparison. Derived fields may be ignored. The same fields, in the same
048 * order, should be used in both {@code compareTo(Object)} and
049 * {@code equals(Object)}.
050 * </p>
051 *
052 * <p>
053 * To use this class write code as follows:
054 * </p>
055 *
056 * <pre>
057 * public class MyClass {
058 *   String field1;
059 *   int field2;
060 *   boolean field3;
061 *
062 *   ...
063 *
064 *   public int compareTo(Object o) {
065 *     MyClass myClass = (MyClass) o;
066 *     return new CompareToBuilder()
067 *       .appendSuper(super.compareTo(o)
068 *       .append(this.field1, myClass.field1)
069 *       .append(this.field2, myClass.field2)
070 *       .append(this.field3, myClass.field3)
071 *       .toComparison();
072 *   }
073 * }
074 * </pre>
075 *
076 * <p>
077 * Values are compared in the order they are appended to the builder. If any comparison returns
078 * a non-zero result, then that value will be the result returned by {@code toComparison()} and all
079 * subsequent comparisons are skipped.
080 * </p>
081 *
082 * <p>
083 * Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
084 * reflection to determine the fields to append. Because fields can be private,
085 * {@code reflectionCompare} uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
086 * bypass normal access control checks. This will fail under a security manager,
087 * unless the appropriate permissions are set up correctly. It is also
088 * slower than appending explicitly.
089 * </p>
090 * <p>
091 * See also {@link AbstractBuilder#setForceAccessible(boolean)}
092 * </p>
093 * <p>
094 * A typical implementation of {@code compareTo(Object)} using
095 * {@code reflectionCompare} looks like:
096 * </p>
097
098 * <pre>
099 * public int compareTo(Object o) {
100 *   return CompareToBuilder.reflectionCompare(this, o);
101 * }
102 * </pre>
103 *
104 * <p>
105 * The reflective methods compare object fields in the order returned by
106 * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those
107 * of its parent classes (in order from the bottom to the top of the class hierarchy).
108 * </p>
109 *
110 * @see Comparable
111 * @see Object#equals(Object)
112 * @see Object#hashCode()
113 * @see EqualsBuilder
114 * @see HashCodeBuilder
115 * @see AbstractBuilder#setForceAccessible(boolean)
116 * @since 1.0
117 */
118public class CompareToBuilder extends AbstractReflection implements Builder<Integer> {
119
120    /**
121     * Builds instances of CompareToBuilder.
122     */
123    public static class Builder extends AbstractBuilder<Builder> {
124
125        /**
126         * Constructs a new Builder instance.
127         */
128        private Builder() {
129            // empty
130        }
131
132        @Override
133        public CompareToBuilder get() {
134            return new CompareToBuilder(this);
135        }
136
137    }
138
139    /**
140     * A registry of objects to detect cyclical object references, avoid infinite loops, and stack overflows.
141     */
142    private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = ThreadLocal.withInitial(HashSet::new);
143
144    /**
145     * Constructs a new Builder.
146     *
147     * @return A new Builder.
148     */
149    public static Builder builder() {
150        return new Builder();
151    }
152
153    /**
154     * Gets the registry of object pairs being traversed by the reflection
155     * methods in the current thread.
156     *
157     * @return Set the registry of objects being traversed.
158     */
159    static Set<Pair<IDKey, IDKey>> getRegistry() {
160        return REGISTRY.get();
161    }
162
163    /**
164     * Tests whether the registry contains the given object pair.
165     * <p>
166     * Used by the reflection methods to avoid infinite loops.
167     * Objects might be swapped therefore a check is needed if the object pair
168     * is registered in the given or swapped order.
169     * </p>
170     *
171     * @param lhs {@code this} object to lookup in registry.
172     * @param rhs The other object to lookup on registry.
173     * @return boolean {@code true} if the registry contains the given object.
174     */
175    static boolean isRegistered(final Object lhs, final Object rhs) {
176        return isRegistered(lhs, rhs, getRegistry());
177    }
178
179    /**
180     * Appends to {@code builder} the comparison of {@code lhs}
181     * to {@code rhs} using the fields defined in {@code clazz}.
182     *
183     * @param lhs  left-hand side object.
184     * @param rhs  right-hand side object.
185     * @param clazz  {@link Class} that defines fields to be compared.
186     * @param builder  {@link CompareToBuilder} to append to.
187     * @param useTransients  whether to compare transient fields.
188     * @param excludeFields  fields to exclude.
189     * @param forceAccessible Whether to set fields' accessible flags.
190     */
191    private static void reflectionAppend(
192        final Object lhs,
193        final Object rhs,
194        final Class<?> clazz,
195        final CompareToBuilder builder,
196        final boolean useTransients,
197        final String[] excludeFields,
198        final boolean forceAccessible) {
199
200        final Field[] fields = clazz.getDeclaredFields();
201        for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
202            final Field field = fields[i];
203            final String name = field.getName();
204            if (!ArrayUtils.contains(excludeFields, name)
205                && !name.contains("$")
206                && (useTransients || !Modifier.isTransient(field.getModifiers()))
207                && !Modifier.isStatic(field.getModifiers())) {
208                if (setAccessible(forceAccessible, field)) {
209                    // IllegalAccessException can't happen. Would get a Security exception instead.
210                    // Throw a runtime exception in case the impossible happens.
211                    builder.append(Reflection.getUnchecked(field, lhs), Reflection.getUnchecked(field, rhs));
212                }
213            }
214        }
215    }
216
217    /**
218     * Compares two {@link Object}s via reflection.
219     * <p>
220     * Fields can be private, thus {@code AccessibleObject.setAccessible} is used to bypass normal access control checks. This will fail under a security
221     * manager unless the appropriate permissions are set.
222     * </p>
223     * <ul>
224     * <li>Static fields will not be compared</li>
225     * <li>Transient members will be not be compared, as they are likely derived fields</li>
226     * <li>Superclass fields will be compared</li>
227     * </ul>
228     * <p>
229     * If both {@code lhs} and {@code rhs} are {@code null}, they are considered equal.
230     * </p>
231     *
232     * @param lhs left-hand side object.
233     * @param rhs right-hand side object.
234     * @return A negative integer, zero, or a positive integer as {@code lhs} is less than, equal to, or greater than {@code rhs}.
235     * @throws NullPointerException Thrown if either (but not both) parameters are {@code null}.
236     * @throws ClassCastException   Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
237     */
238    public static int reflectionCompare(final Object lhs, final Object rhs) {
239        return reflectionCompare(lhs, rhs, false, null);
240    }
241
242    /**
243     * Compares two {@link Object}s via reflection.
244     * <p>
245     * Fields can be private, thus {@code AccessibleObject.setAccessible} is used to bypass normal access control checks. This will fail under a security
246     * manager unless the appropriate permissions are set.
247     * </p>
248     * <ul>
249     * <li>Static fields will not be compared</li>
250     * <li>If {@code compareTransients} is {@code true}, compares transient members. Otherwise ignores them, as they are likely derived fields.</li>
251     * <li>Superclass fields will be compared</li>
252     * </ul>
253     * <p>
254     * If both {@code lhs} and {@code rhs} are {@code null}, they are considered equal.
255     * </p>
256     *
257     * @param lhs               left-hand side object.
258     * @param rhs               right-hand side object.
259     * @param compareTransients whether to compare transient fields.
260     * @return A negative integer, zero, or a positive integer as {@code lhs} is less than, equal to, or greater than {@code rhs}.
261     * @throws NullPointerException Thrown if either {@code lhs} or {@code rhs} (but not both) is {@code null}.
262     * @throws ClassCastException   Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
263     */
264    public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) {
265        return reflectionCompare(lhs, rhs, compareTransients, null);
266    }
267
268    /**
269     * Compares two {@link Object}s via reflection.
270     * <p>
271     * Fields can be private, thus {@code AccessibleObject.setAccessible} is used to bypass normal access control checks. This will fail under a security
272     * manager unless the appropriate permissions are set.
273     * </p>
274     * <ul>
275     * <li>Static fields will not be compared</li>
276     * <li>If the {@code compareTransients} is {@code true}, compares transient members. Otherwise ignores them, as they are likely derived fields.</li>
277     * <li>Compares superclass fields up to and including {@code reflectUpToClass}. If {@code reflectUpToClass} is {@code null}, compares all superclass
278     * fields.</li>
279     * </ul>
280     * <p>
281     * If both {@code lhs} and {@code rhs} are {@code null}, they are considered equal.
282     * </p>
283     *
284     * @param lhs               left-hand side object.
285     * @param rhs               right-hand side object.
286     * @param compareTransients whether to compare transient fields.
287     * @param reflectUpToClass  last superclass for which fields are compared.
288     * @param excludeFields     fields to exclude.
289     * @return A negative integer, zero, or a positive integer as {@code lhs} is less than, equal to, or greater than {@code rhs}.
290     * @throws NullPointerException Thrown if either {@code lhs} or {@code rhs} (but not both) is {@code null}.
291     * @throws ClassCastException   Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
292     * @since 2.2 (2.0 as {@code reflectionCompare(Object, Object, boolean, Class)}).
293     */
294    public static int reflectionCompare(
295        final Object lhs,
296        final Object rhs,
297        final boolean compareTransients,
298        final Class<?> reflectUpToClass,
299        final String... excludeFields) {
300        if (lhs == rhs) {
301            return 0;
302        }
303        Objects.requireNonNull(lhs, "lhs");
304        Objects.requireNonNull(rhs, "rhs");
305        Class<?> lhsClazz = lhs.getClass();
306        if (!lhsClazz.isInstance(rhs)) {
307            throw new ClassCastException();
308        }
309        final CompareToBuilder compareToBuilder = new CompareToBuilder();
310        reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields, AbstractReflection.getForceAccessible());
311        while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
312            lhsClazz = lhsClazz.getSuperclass();
313            reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields, AbstractReflection.getForceAccessible());
314        }
315        return compareToBuilder.toComparison();
316    }
317
318    /**
319     * Compares two {@link Object}s via reflection.
320     * <p>
321     * Fields can be private, thus {@code AccessibleObject.setAccessible} is used to bypass normal access control checks. This will fail under a security
322     * manager unless the appropriate permissions are set.
323     * </p>
324     * <ul>
325     * <li>Static fields will not be compared</li>
326     * <li>If {@code compareTransients} is {@code true}, compares transient members. Otherwise ignores them, as they are likely derived fields.</li>
327     * <li>Superclass fields will be compared</li>
328     * </ul>
329     * <p>
330     * If both {@code lhs} and {@code rhs} are {@code null}, they are considered equal.
331     * </p>
332     *
333     * @param lhs           left-hand side object.
334     * @param rhs           right-hand side object.
335     * @param excludeFields Collection of String fields to exclude.
336     * @return A negative integer, zero, or a positive integer as {@code lhs} is less than, equal to, or greater than {@code rhs}.
337     * @throws NullPointerException Thrown if either {@code lhs} or {@code rhs} (but not both) is {@code null}.
338     * @throws ClassCastException   Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
339     * @since 2.2
340     */
341    public static int reflectionCompare(final Object lhs, final Object rhs, final Collection<String> excludeFields) {
342        return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
343    }
344
345    /**
346     * Compares two {@link Object}s via reflection.
347     * <p>
348     * Fields can be private, thus {@code AccessibleObject.setAccessible} is used to bypass normal access control checks. This will fail under a security
349     * manager unless the appropriate permissions are set.
350     * </p>
351     * <ul>
352     * <li>Static fields will not be compared</li>
353     * <li>If {@code compareTransients} is {@code true}, compares transient members. Otherwise ignores them, as they are likely derived fields.</li>
354     * <li>Superclass fields will be compared</li>
355     * </ul>
356     * <p>
357     * If both {@code lhs} and {@code rhs} are {@code null}, they are considered equal.
358     * </p>
359     *
360     * @param lhs           left-hand side object.
361     * @param rhs           right-hand side object.
362     * @param excludeFields array of fields to exclude.
363     * @return A negative integer, zero, or a positive integer as {@code lhs} is less than, equal to, or greater than {@code rhs}.
364     * @throws NullPointerException Thrown if either {@code lhs} or {@code rhs} (but not both) is {@code null}.
365     * @throws ClassCastException   Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
366     * @since 2.2
367     */
368    public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) {
369        return reflectionCompare(lhs, rhs, false, null, excludeFields);
370    }
371
372    /**
373     * Registers the given object pair. Used by the reflection methods to avoid infinite loops.
374     *
375     * @param lhs {@code this} object to register.
376     * @param rhs The other object to register.
377     */
378    private static void register(final Object lhs, final Object rhs) {
379        register(lhs, rhs, getRegistry());
380    }
381
382    /**
383     * Unregisters the given object pair.
384     * <p>
385     * Used by the reflection methods to avoid infinite loops.
386     * </p>
387     *
388     * @param lhs {@code this} object to unregister.
389     * @param rhs The other object to unregister.
390     */
391    private static void unregister(final Object lhs, final Object rhs) {
392        unregister(lhs, rhs, getRegistry(), REGISTRY);
393    }
394
395    /**
396     * Current state of the comparison as appended fields are checked.
397     */
398    private int comparison;
399
400    /**
401     * Constructor for CompareToBuilder.
402     * <p>
403     * Starts off assuming that the objects are equal. Multiple calls are then made to the various append methods, followed by a call to {@link #toComparison}
404     * to get the result.
405     * </p>
406     */
407    public CompareToBuilder() {
408        super(builder());
409        comparison = 0;
410    }
411
412    private CompareToBuilder(final Builder builder) {
413        super(builder);
414    }
415
416    /**
417     * Appends to the {@code builder} the comparison of two {@code booleans}s.
418     *
419     * @param lhs left-hand side value.
420     * @param rhs right-hand side value.
421     * @return {@code this} instance.
422     */
423    public CompareToBuilder append(final boolean lhs, final boolean rhs) {
424        if (comparison != 0 || lhs == rhs) {
425            return this;
426        }
427        comparison = lhs ? 1 : -1;
428        return this;
429    }
430
431    /**
432     * Appends to the {@code builder} the deep comparison of two {@code boolean} arrays.
433     * <ol>
434     * <li>Check if arrays are the same using {@code ==}</li>
435     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
436     * <li>Check array length, a shorter length array is less than a longer length array</li>
437     * <li>Check array contents element by element using {@link #append(boolean, boolean)}</li>
438     * </ol>
439     *
440     * @param lhs left-hand side array.
441     * @param rhs right-hand side array.
442     * @return {@code this} instance.
443     */
444    public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) {
445        if (comparison != 0 || lhs == rhs) {
446            return this;
447        }
448        if (lhs == null) {
449            comparison = -1;
450            return this;
451        }
452        if (rhs == null) {
453            comparison = 1;
454            return this;
455        }
456        if (lhs.length != rhs.length) {
457            comparison = lhs.length < rhs.length ? -1 : 1;
458            return this;
459        }
460        for (int i = 0; i < lhs.length && comparison == 0; i++) {
461            append(lhs[i], rhs[i]);
462        }
463        return this;
464    }
465
466    /**
467     * Appends to the {@code builder} the comparison of two {@code byte}s.
468     *
469     * @param lhs left-hand side value.
470     * @param rhs right-hand side value.
471     * @return {@code this} instance.
472     */
473    public CompareToBuilder append(final byte lhs, final byte rhs) {
474        if (comparison != 0) {
475            return this;
476        }
477        comparison = Byte.compare(lhs, rhs);
478        return this;
479    }
480
481    /**
482     * Appends to the {@code builder} the deep comparison of two {@code byte} arrays.
483     * <ol>
484     * <li>Check if arrays are the same using {@code ==}</li>
485     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
486     * <li>Check array length, a shorter length array is less than a longer length array</li>
487     * <li>Check array contents element by element using {@link #append(byte, byte)}</li>
488     * </ol>
489     *
490     * @param lhs left-hand side array.
491     * @param rhs right-hand side array.
492     * @return {@code this} instance.
493     */
494    public CompareToBuilder append(final byte[] lhs, final byte[] rhs) {
495        if (comparison != 0 || lhs == rhs) {
496            return this;
497        }
498        if (lhs == null) {
499            comparison = -1;
500            return this;
501        }
502        if (rhs == null) {
503            comparison = 1;
504            return this;
505        }
506        if (lhs.length != rhs.length) {
507            comparison = lhs.length < rhs.length ? -1 : 1;
508            return this;
509        }
510        for (int i = 0; i < lhs.length && comparison == 0; i++) {
511            append(lhs[i], rhs[i]);
512        }
513        return this;
514    }
515
516    /**
517     * Appends to the {@code builder} the comparison of two {@code char}s.
518     *
519     * @param lhs left-hand side value.
520     * @param rhs right-hand side value.
521     * @return {@code this} instance.
522     */
523    public CompareToBuilder append(final char lhs, final char rhs) {
524        if (comparison != 0) {
525            return this;
526        }
527        comparison = Character.compare(lhs, rhs);
528        return this;
529    }
530
531    /**
532     * Appends to the {@code builder} the deep comparison of two {@code char} arrays.
533     * <ol>
534     * <li>Check if arrays are the same using {@code ==}</li>
535     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
536     * <li>Check array length, a shorter length array is less than a longer length array</li>
537     * <li>Check array contents element by element using {@link #append(char, char)}</li>
538     * </ol>
539     *
540     * @param lhs left-hand side array.
541     * @param rhs right-hand side array.
542     * @return {@code this} instance.
543     */
544    public CompareToBuilder append(final char[] lhs, final char[] rhs) {
545        if (comparison != 0 || lhs == rhs) {
546            return this;
547        }
548        if (lhs == null) {
549            comparison = -1;
550            return this;
551        }
552        if (rhs == null) {
553            comparison = 1;
554            return this;
555        }
556        if (lhs.length != rhs.length) {
557            comparison = lhs.length < rhs.length ? -1 : 1;
558            return this;
559        }
560        for (int i = 0; i < lhs.length && comparison == 0; i++) {
561            append(lhs[i], rhs[i]);
562        }
563        return this;
564    }
565
566    /**
567     * Appends to the {@code builder} the comparison of two {@code double}s.
568     * <p>
569     * This handles NaNs, Infinities, and {@code -0.0}.
570     * </p>
571     * <p>
572     * It is compatible with the hash code generated by {@link HashCodeBuilder}.
573     * </p>
574     *
575     * @param lhs left-hand side value.
576     * @param rhs right-hand side value.
577     * @return {@code this} instance.
578     */
579    public CompareToBuilder append(final double lhs, final double rhs) {
580        if (comparison != 0) {
581            return this;
582        }
583        comparison = Double.compare(lhs, rhs);
584        return this;
585    }
586
587    /**
588     * Appends to the {@code builder} the deep comparison of two {@code double} arrays.
589     * <ol>
590     * <li>Check if arrays are the same using {@code ==}</li>
591     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
592     * <li>Check array length, a shorter length array is less than a longer length array</li>
593     * <li>Check array contents element by element using {@link #append(double, double)}</li>
594     * </ol>
595     *
596     * @param lhs left-hand side array.
597     * @param rhs right-hand side array.
598     * @return {@code this} instance.
599     */
600    public CompareToBuilder append(final double[] lhs, final double[] rhs) {
601        if (comparison != 0 || lhs == rhs) {
602            return this;
603        }
604        if (lhs == null) {
605            comparison = -1;
606            return this;
607        }
608        if (rhs == null) {
609            comparison = 1;
610            return this;
611        }
612        if (lhs.length != rhs.length) {
613            comparison = lhs.length < rhs.length ? -1 : 1;
614            return this;
615        }
616        for (int i = 0; i < lhs.length && comparison == 0; i++) {
617            append(lhs[i], rhs[i]);
618        }
619        return this;
620    }
621
622    /**
623     * Appends to the {@code builder} the comparison of two {@code float}s.
624     * <p>
625     * This handles NaNs, Infinities, and {@code -0.0}.
626     * </p>
627     * <p>
628     * It is compatible with the hash code generated by {@link HashCodeBuilder}.
629     * </p>
630     *
631     * @param lhs left-hand side value.
632     * @param rhs right-hand side value.
633     * @return {@code this} instance.
634     */
635    public CompareToBuilder append(final float lhs, final float rhs) {
636        if (comparison != 0) {
637            return this;
638        }
639        comparison = Float.compare(lhs, rhs);
640        return this;
641    }
642
643    /**
644     * Appends to the {@code builder} the deep comparison of two {@code float} arrays.
645     * <ol>
646     * <li>Check if arrays are the same using {@code ==}</li>
647     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
648     * <li>Check array length, a shorter length array is less than a longer length array</li>
649     * <li>Check array contents element by element using {@link #append(float, float)}</li>
650     * </ol>
651     *
652     * @param lhs left-hand side array.
653     * @param rhs right-hand side array.
654     * @return {@code this} instance.
655     */
656    public CompareToBuilder append(final float[] lhs, final float[] rhs) {
657        if (comparison != 0 || lhs == rhs) {
658            return this;
659        }
660        if (lhs == null) {
661            comparison = -1;
662            return this;
663        }
664        if (rhs == null) {
665            comparison = 1;
666            return this;
667        }
668        if (lhs.length != rhs.length) {
669            comparison = lhs.length < rhs.length ? -1 : 1;
670            return this;
671        }
672        for (int i = 0; i < lhs.length && comparison == 0; i++) {
673            append(lhs[i], rhs[i]);
674        }
675        return this;
676    }
677
678    /**
679     * Appends to the {@code builder} the comparison of two {@code int}s.
680     *
681     * @param lhs left-hand side value.
682     * @param rhs right-hand side value.
683     * @return {@code this} instance.
684     */
685    public CompareToBuilder append(final int lhs, final int rhs) {
686        if (comparison != 0) {
687            return this;
688        }
689        comparison = Integer.compare(lhs, rhs);
690        return this;
691    }
692
693    /**
694     * Appends to the {@code builder} the deep comparison of two {@code int} arrays.
695     * <ol>
696     * <li>Check if arrays are the same using {@code ==}</li>
697     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
698     * <li>Check array length, a shorter length array is less than a longer length array</li>
699     * <li>Check array contents element by element using {@link #append(int, int)}</li>
700     * </ol>
701     *
702     * @param lhs left-hand side array.
703     * @param rhs right-hand side array.
704     * @return {@code this} instance.
705     */
706    public CompareToBuilder append(final int[] lhs, final int[] rhs) {
707        if (comparison != 0 || lhs == rhs) {
708            return this;
709        }
710        if (lhs == null) {
711            comparison = -1;
712            return this;
713        }
714        if (rhs == null) {
715            comparison = 1;
716            return this;
717        }
718        if (lhs.length != rhs.length) {
719            comparison = lhs.length < rhs.length ? -1 : 1;
720            return this;
721        }
722        for (int i = 0; i < lhs.length && comparison == 0; i++) {
723            append(lhs[i], rhs[i]);
724        }
725        return this;
726    }
727
728    /**
729     * Appends to the {@code builder} the comparison of two {@code long}s.
730     *
731     * @param lhs left-hand side value.
732     * @param rhs right-hand side value.
733     * @return {@code this} instance.
734     */
735    public CompareToBuilder append(final long lhs, final long rhs) {
736        if (comparison != 0) {
737            return this;
738        }
739        comparison = Long.compare(lhs, rhs);
740        return this;
741    }
742
743    /**
744     * Appends to the {@code builder} the deep comparison of two {@code long} arrays.
745     * <ol>
746     * <li>Check if arrays are the same using {@code ==}</li>
747     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
748     * <li>Check array length, a shorter length array is less than a longer length array</li>
749     * <li>Check array contents element by element using {@link #append(long, long)}</li>
750     * </ol>
751     *
752     * @param lhs left-hand side array.
753     * @param rhs right-hand side array.
754     * @return {@code this} instance.
755     */
756    public CompareToBuilder append(final long[] lhs, final long[] rhs) {
757        if (comparison != 0 || lhs == rhs) {
758            return this;
759        }
760        if (lhs == null) {
761            comparison = -1;
762            return this;
763        }
764        if (rhs == null) {
765            comparison = 1;
766            return this;
767        }
768        if (lhs.length != rhs.length) {
769            comparison = lhs.length < rhs.length ? -1 : 1;
770            return this;
771        }
772        for (int i = 0; i < lhs.length && comparison == 0; i++) {
773            append(lhs[i], rhs[i]);
774        }
775        return this;
776    }
777
778    /**
779     * Appends to the {@code builder} the comparison of two {@link Object}s.
780     * <ol>
781     * <li>Check if {@code lhs == rhs}</li>
782     * <li>Check if either {@code lhs} or {@code rhs} is {@code null}, a {@code null} object is less than a non-{@code null} object</li>
783     * <li>Check the object contents</li>
784     * </ol>
785     * <p>
786     * {@code lhs} must either be an array or implement {@link Comparable}.
787     * </p>
788     *
789     * @param lhs left-hand side object.
790     * @param rhs right-hand side object.
791     * @return {@code this} instance.
792     * @throws ClassCastException Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
793     */
794    public CompareToBuilder append(final Object lhs, final Object rhs) {
795        return append(lhs, rhs, null);
796    }
797
798    /**
799     * Appends to the {@code builder} the comparison of two {@link Object}s.
800     * <ol>
801     * <li>Check if {@code lhs == rhs}</li>
802     * <li>Check if either {@code lhs} or {@code rhs} is {@code null}, a {@code null} object is less than a non-{@code null} object</li>
803     * <li>Check the object contents</li>
804     * </ol>
805     * <p>
806     * If {@code lhs} is an array, array comparison methods will be used. Otherwise {@code comparator} will be used to compare the objects. If
807     * {@code comparator} is {@code null}, {@code lhs} must implement {@link Comparable} instead.
808     * </p>
809     *
810     * @param lhs        left-hand side object.
811     * @param rhs        right-hand side object.
812     * @param comparator {@link Comparator} used to compare the objects, {@code null} means treat lhs as {@link Comparable}
813     * @return {@code this} instance.
814     * @throws ClassCastException Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
815     * @since 2.0
816     */
817    public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator<?> comparator) {
818        if (comparison != 0 || lhs == rhs) {
819            return this;
820        }
821        if (lhs == null) {
822            comparison = -1;
823            return this;
824        }
825        if (rhs == null) {
826            comparison = 1;
827            return this;
828        }
829        if (isRegistered(lhs, rhs)) {
830            return this;
831        }
832        try {
833            register(lhs, rhs);
834            if (ObjectUtils.isArray(lhs)) {
835                // factor out array case in order to keep method small enough to be inlined
836                appendArray(lhs, rhs, comparator);
837            } else // the simple case, not an array, just test the element
838            if (comparator == null) {
839                @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
840                final Comparable<Object> comparable = (Comparable<Object>) lhs;
841                comparison = comparable.compareTo(rhs);
842            } else {
843                @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
844                final Comparator<Object> comparator2 = (Comparator<Object>) comparator;
845                comparison = comparator2.compare(lhs, rhs);
846            }
847            return this;
848        } finally {
849            unregister(lhs, rhs);
850        }
851    }
852
853    /**
854     * Appends to the {@code builder} the deep comparison of two {@link Object} arrays.
855     * <ol>
856     * <li>Check if arrays are the same using {@code ==}</li>
857     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
858     * <li>Check array length, a short length array is less than a long length array</li>
859     * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
860     * </ol>
861     * <p>
862     * This method will also will be called for the top level of multi-dimensional, ragged, and multi-typed arrays.
863     * </p>
864     *
865     * @param lhs left-hand side array.
866     * @param rhs right-hand side array.
867     * @return {@code this} instance.
868     * @throws ClassCastException Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
869     */
870    public CompareToBuilder append(final Object[] lhs, final Object[] rhs) {
871        return append(lhs, rhs, null);
872    }
873
874    /**
875     * Appends to the {@code builder} the deep comparison of two {@link Object} arrays.
876     * <ol>
877     * <li>Check if arrays are the same using {@code ==}</li>
878     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
879     * <li>Check array length, a short length array is less than a long length array</li>
880     * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
881     * </ol>
882     * <p>
883     * This method will also will be called for the top level of multi-dimensional, ragged, and multi-typed arrays.
884     * </p>
885     *
886     * @param lhs        left-hand side array.
887     * @param rhs        right-hand side array.
888     * @param comparator {@link Comparator} to use to compare the array elements, {@code null} means to treat {@code lhs} elements as {@link Comparable}.
889     * @return {@code this} instance.
890     * @throws ClassCastException Thrown if {@code rhs} is not assignment-compatible with {@code lhs}.
891     * @since 2.0
892     */
893    public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator<?> comparator) {
894        if (comparison != 0 || lhs == rhs) {
895            return this;
896        }
897        if (lhs == null) {
898            comparison = -1;
899            return this;
900        }
901        if (rhs == null) {
902            comparison = 1;
903            return this;
904        }
905        if (lhs.length != rhs.length) {
906            comparison = lhs.length < rhs.length ? -1 : 1;
907            return this;
908        }
909        for (int i = 0; i < lhs.length && comparison == 0; i++) {
910            append(lhs[i], rhs[i], comparator);
911        }
912        return this;
913    }
914
915    /**
916     * Appends to the {@code builder} the comparison of two {@code short}s.
917     *
918     * @param lhs left-hand side value.
919     * @param rhs right-hand side value.
920     * @return {@code this} instance.
921     */
922    public CompareToBuilder append(final short lhs, final short rhs) {
923        if (comparison != 0) {
924            return this;
925        }
926        comparison = Short.compare(lhs, rhs);
927        return this;
928    }
929
930    /**
931     * Appends to the {@code builder} the deep comparison of two {@code short} arrays.
932     * <ol>
933     * <li>Check if arrays are the same using {@code ==}</li>
934     * <li>Check if for {@code null}, {@code null} is less than non-{@code null}</li>
935     * <li>Check array length, a shorter length array is less than a longer length array</li>
936     * <li>Check array contents element by element using {@link #append(short, short)}</li>
937     * </ol>
938     *
939     * @param lhs left-hand side array.
940     * @param rhs right-hand side array.
941     * @return {@code this} instance.
942     */
943    public CompareToBuilder append(final short[] lhs, final short[] rhs) {
944        if (comparison != 0 || lhs == rhs) {
945            return this;
946        }
947        if (lhs == null) {
948            comparison = -1;
949            return this;
950        }
951        if (rhs == null) {
952            comparison = 1;
953            return this;
954        }
955        if (lhs.length != rhs.length) {
956            comparison = lhs.length < rhs.length ? -1 : 1;
957            return this;
958        }
959        for (int i = 0; i < lhs.length && comparison == 0; i++) {
960            append(lhs[i], rhs[i]);
961        }
962        return this;
963    }
964
965    private void appendArray(final Object lhs, final Object rhs, final Comparator<?> comparator) {
966        // switch on type of array, to dispatch to the correct handler
967        // handles multidimensional arrays
968        // throws a ClassCastException if rhs is not the correct array type
969        if (lhs instanceof long[]) {
970            append((long[]) lhs, (long[]) rhs);
971        } else if (lhs instanceof int[]) {
972            append((int[]) lhs, (int[]) rhs);
973        } else if (lhs instanceof short[]) {
974            append((short[]) lhs, (short[]) rhs);
975        } else if (lhs instanceof char[]) {
976            append((char[]) lhs, (char[]) rhs);
977        } else if (lhs instanceof byte[]) {
978            append((byte[]) lhs, (byte[]) rhs);
979        } else if (lhs instanceof double[]) {
980            append((double[]) lhs, (double[]) rhs);
981        } else if (lhs instanceof float[]) {
982            append((float[]) lhs, (float[]) rhs);
983        } else if (lhs instanceof boolean[]) {
984            append((boolean[]) lhs, (boolean[]) rhs);
985        } else {
986            // not an array of primitives
987            // throws a ClassCastException if rhs is not an array
988            append((Object[]) lhs, (Object[]) rhs, comparator);
989        }
990    }
991
992    /**
993     * Appends to the {@code builder} the {@code compareTo(Object)} result of the superclass.
994     *
995     * @param superCompareTo result of calling {@code super.compareTo(Object)}.
996     * @return {@code this} instance.
997     * @since 2.0
998     */
999    public CompareToBuilder appendSuper(final int superCompareTo) {
1000        if (comparison != 0) {
1001            return this;
1002        }
1003        comparison = superCompareTo;
1004        return this;
1005    }
1006
1007    /**
1008     * Returns a negative Integer, a positive Integer, or zero as the {@code builder} has judged the "left-hand" side as less than, greater than, or equal to
1009     * the "right-hand" side.
1010     *
1011     * @return final comparison result as an Integer.
1012     * @see #toComparison()
1013     * @since 3.0
1014     */
1015    @Override
1016    public Integer build() {
1017        return Integer.valueOf(toComparison());
1018    }
1019
1020    /**
1021     * Returns a negative integer, a positive integer, or zero as the {@code builder} has judged the "left-hand" side as less than, greater than, or equal to
1022     * the "right-hand" side.
1023     *
1024     * @return final comparison result.
1025     * @see #build()
1026     */
1027    public int toComparison() {
1028        return comparison;
1029    }
1030}
1031