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