Source code
Description: source: package: org.apache.commons.lang3.builder, class: CompareToBuilder

    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