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