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