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