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