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