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