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