View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.builder;
18  
19  import java.lang.reflect.AccessibleObject;
20  import java.lang.reflect.Field;
21  import java.lang.reflect.Modifier;
22  import java.util.Collection;
23  import java.util.Comparator;
24  
25  import org.apache.commons.lang3.ArrayUtils;
26  
27  /** 
28   * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods.
29   *
30   * <p>It is consistent with <code>equals(Object)</code> and
31   * <code>hashcode()</code> built with {@link EqualsBuilder} and
32   * {@link HashCodeBuilder}.</p>
33   *
34   * <p>Two Objects that compare equal using <code>equals(Object)</code> should normally
35   * also compare equal using <code>compareTo(Object)</code>.</p>
36   *
37   * <p>All relevant fields should be included in the calculation of the
38   * comparison. Derived fields may be ignored. The same fields, in the same
39   * order, should be used in both <code>compareTo(Object)</code> and
40   * <code>equals(Object)</code>.</p>
41   *
42   * <p>To use this class write code as follows:</p>
43   *
44   * <pre>
45   * public class MyClass {
46   *   String field1;
47   *   int field2;
48   *   boolean field3;
49   *
50   *   ...
51   *
52   *   public int compareTo(Object o) {
53   *     MyClass myClass = (MyClass) o;
54   *     return new CompareToBuilder()
55   *       .appendSuper(super.compareTo(o)
56   *       .append(this.field1, myClass.field1)
57   *       .append(this.field2, myClass.field2)
58   *       .append(this.field3, myClass.field3)
59   *       .toComparison();
60   *   }
61   * }
62   * </pre>
63   * 
64   * <p>Values are compared in the order they are appended to the builder. If any comparison returns
65   * a non-zero result, then that value will be the result returned by {@code toComparison()} and all
66   * subsequent comparisons are skipped.</p>
67   *
68   * <p>Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
69   * reflection to determine the fields to append. Because fields can be private,
70   * <code>reflectionCompare</code> uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
71   * bypass normal access control checks. This will fail under a security manager,
72   * unless the appropriate permissions are set up correctly. It is also
73   * slower than appending explicitly.</p>
74   *
75   * <p>A typical implementation of <code>compareTo(Object)</code> using
76   * <code>reflectionCompare</code> looks like:</p>
77  
78   * <pre>
79   * public int compareTo(Object o) {
80   *   return CompareToBuilder.reflectionCompare(this, o);
81   * }
82   * </pre>
83   * 
84   * <p>The reflective methods compare object fields in the order returned by 
85   * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those
86   * of its parent classes (in order from the bottom to the top of the class hierarchy).</p>
87   *
88   * @see java.lang.Comparable
89   * @see java.lang.Object#equals(Object)
90   * @see java.lang.Object#hashCode()
91   * @see EqualsBuilder
92   * @see HashCodeBuilder
93   * @since 1.0
94   */
95  public class CompareToBuilder implements Builder<Integer> {
96      
97      /**
98       * Current state of the comparison as appended fields are checked.
99       */
100     private int comparison;
101 
102     /**
103      * <p>Constructor for CompareToBuilder.</p>
104      *
105      * <p>Starts off assuming that the objects are equal. Multiple calls are 
106      * then made to the various append methods, followed by a call to 
107      * {@link #toComparison} to get the result.</p>
108      */
109     public CompareToBuilder() {
110         super();
111         comparison = 0;
112     }
113 
114     //-----------------------------------------------------------------------
115     /** 
116      * <p>Compares two <code>Object</code>s via reflection.</p>
117      *
118      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
135      *  is less than, equal to, or greater than <code>rhs</code>
136      * @throws NullPointerException  if either (but not both) parameters are
137      *  <code>null</code>
138      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
139      *  with <code>lhs</code>
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</code>s via reflection.</p>
147      *
148      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
167      *  is less than, equal to, or greater than <code>rhs</code>
168      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
169      *  (but not both) is <code>null</code>
170      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
171      *  with <code>lhs</code>
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</code>s via reflection.</p>
179      *
180      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
199      *  is less than, equal to, or greater than <code>rhs</code>
200      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
201      *  (but not both) is <code>null</code>
202      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
203      *  with <code>lhs</code>
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</code>s via reflection.</p>
212      *
213      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
232      *  is less than, equal to, or greater than <code>rhs</code>
233      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
234      *  (but not both) is <code>null</code>
235      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
236      *  with <code>lhs</code>
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</code>s via reflection.</p>
245      *
246      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code>.
256      *     If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
257      * </ul>
258      *
259      * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
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</code>
268      *  is less than, equal to, or greater than <code>rhs</code>
269      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
270      *  (but not both) is <code>null</code>
271      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
272      *  with <code>lhs</code>
273      * @since 2.2 (2.0 as <code>reflectionCompare(Object, Object, boolean, Class)</code>)
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         if (lhs == null || rhs == null) {
286             throw new NullPointerException();
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</code> the comparison of <code>lhs</code>
303      * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
304      * 
305      * @param lhs  left-hand object
306      * @param rhs  right-hand object
307      * @param clazz  <code>Class</code> that defines fields to be compared
308      * @param builder  <code>CompareToBuilder</code> 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</code> the <code>compareTo(Object)</code>
342      * result of the superclass.</p>
343      *
344      * @param superCompareTo  result of calling <code>super.compareTo(Object)</code>
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</code> the comparison of
359      * two <code>Object</code>s.</p>
360      *
361      * <ol>
362      * <li>Check if <code>lhs == rhs</code></li>
363      * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
364      *     a <code>null</code> object is less than a non-<code>null</code> object</li>
365      * <li>Check the object contents</li>
366      * </ol>
367      * 
368      * <p><code>lhs</code> 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</code> is not assignment-compatible
374      *  with <code>lhs</code>
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</code> the comparison of
382      * two <code>Object</code>s.</p>
383      *
384      * <ol>
385      * <li>Check if <code>lhs == rhs</code></li>
386      * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
387      *     a <code>null</code> object is less than a non-<code>null</code> object</li>
388      * <li>Check the object contents</li>
389      * </ol>
390      *
391      * <p>If <code>lhs</code> is an array, array comparison methods will be used.
392      * Otherwise <code>comparator</code> will be used to compare the objects.
393      * If <code>comparator</code> is <code>null</code>, <code>lhs</code> 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</code> used to compare the objects,
399      *  <code>null</code> means treat lhs as <code>Comparable</code>
400      * @return this - used to chain append calls
401      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
402      *  with <code>lhs</code>
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             // switch on type of array, to dispatch to the correct handler
422             // handles multi dimensional arrays
423             // throws a ClassCastException if rhs is not the correct array type
424             if (lhs instanceof long[]) {
425                 append((long[]) lhs, (long[]) rhs);
426             } else if (lhs instanceof int[]) {
427                 append((int[]) lhs, (int[]) rhs);
428             } else if (lhs instanceof short[]) {
429                 append((short[]) lhs, (short[]) rhs);
430             } else if (lhs instanceof char[]) {
431                 append((char[]) lhs, (char[]) rhs);
432             } else if (lhs instanceof byte[]) {
433                 append((byte[]) lhs, (byte[]) rhs);
434             } else if (lhs instanceof double[]) {
435                 append((double[]) lhs, (double[]) rhs);
436             } else if (lhs instanceof float[]) {
437                 append((float[]) lhs, (float[]) rhs);
438             } else if (lhs instanceof boolean[]) {
439                 append((boolean[]) lhs, (boolean[]) rhs);
440             } else {
441                 // not an array of primitives
442                 // throws a ClassCastException if rhs is not an array
443                 append((Object[]) lhs, (Object[]) rhs, comparator);
444             }
445         } else {
446             // the simple case, not an array, just test the element
447             if (comparator == null) {
448                 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
449                 final Comparable<Object> comparable = (Comparable<Object>) lhs;
450                 comparison = comparable.compareTo(rhs);
451             } else {
452                 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
453                 final Comparator<Object> comparator2 = (Comparator<Object>) comparator;
454                 comparison = comparator2.compare(lhs, rhs);
455             }
456         }
457         return this;
458     }
459 
460     //-------------------------------------------------------------------------
461     /**
462      * Appends to the <code>builder</code> the comparison of
463      * two <code>long</code>s.
464      *
465      * @param lhs  left-hand value
466      * @param rhs  right-hand value
467      * @return this - used to chain append calls
468      */
469     public CompareToBuilder append(final long lhs, final long rhs) {
470         if (comparison != 0) {
471             return this;
472         }
473         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
474         return this;
475     }
476 
477     /**
478      * Appends to the <code>builder</code> the comparison of
479      * two <code>int</code>s.
480      *
481      * @param lhs  left-hand value
482      * @param rhs  right-hand value
483      * @return this - used to chain append calls
484      */
485     public CompareToBuilder append(final int lhs, final int rhs) {
486         if (comparison != 0) {
487             return this;
488         }
489         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
490         return this;
491     }
492 
493     /**
494      * Appends to the <code>builder</code> the comparison of
495      * two <code>short</code>s.
496      * 
497      * @param lhs  left-hand value
498      * @param rhs  right-hand value
499      * @return this - used to chain append calls
500      */
501     public CompareToBuilder append(final short lhs, final short rhs) {
502         if (comparison != 0) {
503             return this;
504         }
505         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
506         return this;
507     }
508 
509     /**
510      * Appends to the <code>builder</code> the comparison of
511      * two <code>char</code>s.
512      *
513      * @param lhs  left-hand value
514      * @param rhs  right-hand value
515      * @return this - used to chain append calls
516      */
517     public CompareToBuilder append(final char lhs, final char rhs) {
518         if (comparison != 0) {
519             return this;
520         }
521         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
522         return this;
523     }
524 
525     /**
526      * Appends to the <code>builder</code> the comparison of
527      * two <code>byte</code>s.
528      * 
529      * @param lhs  left-hand value
530      * @param rhs  right-hand value
531      * @return this - used to chain append calls
532      */
533     public CompareToBuilder append(final byte lhs, final byte rhs) {
534         if (comparison != 0) {
535             return this;
536         }
537         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
538         return this;
539     }
540 
541     /**
542      * <p>Appends to the <code>builder</code> the comparison of
543      * two <code>double</code>s.</p>
544      *
545      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
546      *
547      * <p>It is compatible with the hash code generated by
548      * <code>HashCodeBuilder</code>.</p>
549      *
550      * @param lhs  left-hand value
551      * @param rhs  right-hand value
552      * @return this - used to chain append calls
553      */
554     public CompareToBuilder append(final double lhs, final double rhs) {
555         if (comparison != 0) {
556             return this;
557         }
558         comparison = Double.compare(lhs, rhs);
559         return this;
560     }
561 
562     /**
563      * <p>Appends to the <code>builder</code> the comparison of
564      * two <code>float</code>s.</p>
565      *
566      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
567      *
568      * <p>It is compatible with the hash code generated by
569      * <code>HashCodeBuilder</code>.</p>
570      *
571      * @param lhs  left-hand value
572      * @param rhs  right-hand value
573      * @return this - used to chain append calls
574      */
575     public CompareToBuilder append(final float lhs, final float rhs) {
576         if (comparison != 0) {
577             return this;
578         }
579         comparison = Float.compare(lhs, rhs);
580         return this;
581     }
582 
583     /**
584      * Appends to the <code>builder</code> the comparison of
585      * two <code>booleans</code>s.
586      *
587      * @param lhs  left-hand value
588      * @param rhs  right-hand value
589      * @return this - used to chain append calls
590       */
591     public CompareToBuilder append(final boolean lhs, final boolean rhs) {
592         if (comparison != 0) {
593             return this;
594         }
595         if (lhs == rhs) {
596             return this;
597         }
598         if (lhs == false) {
599             comparison = -1;
600         } else {
601             comparison = +1;
602         }
603         return this;
604     }
605 
606     //-----------------------------------------------------------------------
607     /**
608      * <p>Appends to the <code>builder</code> the deep comparison of
609      * two <code>Object</code> arrays.</p>
610      *
611      * <ol>
612      *  <li>Check if arrays are the same using <code>==</code></li>
613      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
614      *  <li>Check array length, a short length array is less than a long length array</li>
615      *  <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
616      * </ol>
617      *
618      * <p>This method will also will be called for the top level of multi-dimensional,
619      * ragged, and multi-typed arrays.</p>
620      *
621      * @param lhs  left-hand array
622      * @param rhs  right-hand array
623      * @return this - used to chain append calls
624      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
625      *  with <code>lhs</code>
626      */
627     public CompareToBuilder append(final Object[] lhs, final Object[] rhs) {
628         return append(lhs, rhs, null);
629     }
630     
631     /**
632      * <p>Appends to the <code>builder</code> the deep comparison of
633      * two <code>Object</code> arrays.</p>
634      *
635      * <ol>
636      *  <li>Check if arrays are the same using <code>==</code></li>
637      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
638      *  <li>Check array length, a short length array is less than a long length array</li>
639      *  <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
640      * </ol>
641      *
642      * <p>This method will also will be called for the top level of multi-dimensional,
643      * ragged, and multi-typed arrays.</p>
644      *
645      * @param lhs  left-hand array
646      * @param rhs  right-hand array
647      * @param comparator  <code>Comparator</code> to use to compare the array elements,
648      *  <code>null</code> means to treat <code>lhs</code> elements as <code>Comparable</code>.
649      * @return this - used to chain append calls
650      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
651      *  with <code>lhs</code>
652      * @since 2.0
653      */
654     public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator<?> comparator) {
655         if (comparison != 0) {
656             return this;
657         }
658         if (lhs == rhs) {
659             return this;
660         }
661         if (lhs == null) {
662             comparison = -1;
663             return this;
664         }
665         if (rhs == null) {
666             comparison = +1;
667             return this;
668         }
669         if (lhs.length != rhs.length) {
670             comparison = (lhs.length < rhs.length) ? -1 : +1;
671             return this;
672         }
673         for (int i = 0; i < lhs.length && comparison == 0; i++) {
674             append(lhs[i], rhs[i], comparator);
675         }
676         return this;
677     }
678 
679     /**
680      * <p>Appends to the <code>builder</code> the deep comparison of
681      * two <code>long</code> arrays.</p>
682      *
683      * <ol>
684      *  <li>Check if arrays are the same using <code>==</code></li>
685      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
686      *  <li>Check array length, a shorter length array is less than a longer length array</li>
687      *  <li>Check array contents element by element using {@link #append(long, long)}</li>
688      * </ol>
689      *
690      * @param lhs  left-hand array
691      * @param rhs  right-hand array
692      * @return this - used to chain append calls
693      */
694     public CompareToBuilder append(final long[] lhs, final long[] rhs) {
695         if (comparison != 0) {
696             return this;
697         }
698         if (lhs == rhs) {
699             return this;
700         }
701         if (lhs == null) {
702             comparison = -1;
703             return this;
704         }
705         if (rhs == null) {
706             comparison = +1;
707             return this;
708         }
709         if (lhs.length != rhs.length) {
710             comparison = (lhs.length < rhs.length) ? -1 : +1;
711             return this;
712         }
713         for (int i = 0; i < lhs.length && comparison == 0; i++) {
714             append(lhs[i], rhs[i]);
715         }
716         return this;
717     }
718 
719     /**
720      * <p>Appends to the <code>builder</code> the deep comparison of
721      * two <code>int</code> arrays.</p>
722      *
723      * <ol>
724      *  <li>Check if arrays are the same using <code>==</code></li>
725      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
726      *  <li>Check array length, a shorter length array is less than a longer length array</li>
727      *  <li>Check array contents element by element using {@link #append(int, int)}</li>
728      * </ol>
729      *
730      * @param lhs  left-hand array
731      * @param rhs  right-hand array
732      * @return this - used to chain append calls
733      */
734     public CompareToBuilder append(final int[] lhs, final int[] rhs) {
735         if (comparison != 0) {
736             return this;
737         }
738         if (lhs == rhs) {
739             return this;
740         }
741         if (lhs == null) {
742             comparison = -1;
743             return this;
744         }
745         if (rhs == null) {
746             comparison = +1;
747             return this;
748         }
749         if (lhs.length != rhs.length) {
750             comparison = (lhs.length < rhs.length) ? -1 : +1;
751             return this;
752         }
753         for (int i = 0; i < lhs.length && comparison == 0; i++) {
754             append(lhs[i], rhs[i]);
755         }
756         return this;
757     }
758 
759     /**
760      * <p>Appends to the <code>builder</code> the deep comparison of
761      * two <code>short</code> arrays.</p>
762      *
763      * <ol>
764      *  <li>Check if arrays are the same using <code>==</code></li>
765      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
766      *  <li>Check array length, a shorter length array is less than a longer length array</li>
767      *  <li>Check array contents element by element using {@link #append(short, short)}</li>
768      * </ol>
769      *
770      * @param lhs  left-hand array
771      * @param rhs  right-hand array
772      * @return this - used to chain append calls
773      */
774     public CompareToBuilder append(final short[] lhs, final short[] rhs) {
775         if (comparison != 0) {
776             return this;
777         }
778         if (lhs == rhs) {
779             return this;
780         }
781         if (lhs == null) {
782             comparison = -1;
783             return this;
784         }
785         if (rhs == null) {
786             comparison = +1;
787             return this;
788         }
789         if (lhs.length != rhs.length) {
790             comparison = (lhs.length < rhs.length) ? -1 : +1;
791             return this;
792         }
793         for (int i = 0; i < lhs.length && comparison == 0; i++) {
794             append(lhs[i], rhs[i]);
795         }
796         return this;
797     }
798 
799     /**
800      * <p>Appends to the <code>builder</code> the deep comparison of
801      * two <code>char</code> arrays.</p>
802      *
803      * <ol>
804      *  <li>Check if arrays are the same using <code>==</code></li>
805      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
806      *  <li>Check array length, a shorter length array is less than a longer length array</li>
807      *  <li>Check array contents element by element using {@link #append(char, char)}</li>
808      * </ol>
809      *
810      * @param lhs  left-hand array
811      * @param rhs  right-hand array
812      * @return this - used to chain append calls
813      */
814     public CompareToBuilder append(final char[] lhs, final char[] rhs) {
815         if (comparison != 0) {
816             return this;
817         }
818         if (lhs == rhs) {
819             return this;
820         }
821         if (lhs == null) {
822             comparison = -1;
823             return this;
824         }
825         if (rhs == null) {
826             comparison = +1;
827             return this;
828         }
829         if (lhs.length != rhs.length) {
830             comparison = (lhs.length < rhs.length) ? -1 : +1;
831             return this;
832         }
833         for (int i = 0; i < lhs.length && comparison == 0; i++) {
834             append(lhs[i], rhs[i]);
835         }
836         return this;
837     }
838 
839     /**
840      * <p>Appends to the <code>builder</code> the deep comparison of
841      * two <code>byte</code> arrays.</p>
842      *
843      * <ol>
844      *  <li>Check if arrays are the same using <code>==</code></li>
845      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
846      *  <li>Check array length, a shorter length array is less than a longer length array</li>
847      *  <li>Check array contents element by element using {@link #append(byte, byte)}</li>
848      * </ol>
849      *
850      * @param lhs  left-hand array
851      * @param rhs  right-hand array
852      * @return this - used to chain append calls
853      */
854     public CompareToBuilder append(final byte[] lhs, final byte[] rhs) {
855         if (comparison != 0) {
856             return this;
857         }
858         if (lhs == rhs) {
859             return this;
860         }
861         if (lhs == null) {
862             comparison = -1;
863             return this;
864         }
865         if (rhs == null) {
866             comparison = +1;
867             return this;
868         }
869         if (lhs.length != rhs.length) {
870             comparison = (lhs.length < rhs.length) ? -1 : +1;
871             return this;
872         }
873         for (int i = 0; i < lhs.length && comparison == 0; i++) {
874             append(lhs[i], rhs[i]);
875         }
876         return this;
877     }
878 
879     /**
880      * <p>Appends to the <code>builder</code> the deep comparison of
881      * two <code>double</code> arrays.</p>
882      *
883      * <ol>
884      *  <li>Check if arrays are the same using <code>==</code></li>
885      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
886      *  <li>Check array length, a shorter length array is less than a longer length array</li>
887      *  <li>Check array contents element by element using {@link #append(double, double)}</li>
888      * </ol>
889      *
890      * @param lhs  left-hand array
891      * @param rhs  right-hand array
892      * @return this - used to chain append calls
893      */
894     public CompareToBuilder append(final double[] lhs, final double[] rhs) {
895         if (comparison != 0) {
896             return this;
897         }
898         if (lhs == rhs) {
899             return this;
900         }
901         if (lhs == null) {
902             comparison = -1;
903             return this;
904         }
905         if (rhs == null) {
906             comparison = +1;
907             return this;
908         }
909         if (lhs.length != rhs.length) {
910             comparison = (lhs.length < rhs.length) ? -1 : +1;
911             return this;
912         }
913         for (int i = 0; i < lhs.length && comparison == 0; i++) {
914             append(lhs[i], rhs[i]);
915         }
916         return this;
917     }
918 
919     /**
920      * <p>Appends to the <code>builder</code> the deep comparison of
921      * two <code>float</code> arrays.</p>
922      *
923      * <ol>
924      *  <li>Check if arrays are the same using <code>==</code></li>
925      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
926      *  <li>Check array length, a shorter length array is less than a longer length array</li>
927      *  <li>Check array contents element by element using {@link #append(float, float)}</li>
928      * </ol>
929      *
930      * @param lhs  left-hand array
931      * @param rhs  right-hand array
932      * @return this - used to chain append calls
933      */
934     public CompareToBuilder append(final float[] lhs, final float[] rhs) {
935         if (comparison != 0) {
936             return this;
937         }
938         if (lhs == rhs) {
939             return this;
940         }
941         if (lhs == null) {
942             comparison = -1;
943             return this;
944         }
945         if (rhs == null) {
946             comparison = +1;
947             return this;
948         }
949         if (lhs.length != rhs.length) {
950             comparison = (lhs.length < rhs.length) ? -1 : +1;
951             return this;
952         }
953         for (int i = 0; i < lhs.length && comparison == 0; i++) {
954             append(lhs[i], rhs[i]);
955         }
956         return this;
957     }
958 
959     /**
960      * <p>Appends to the <code>builder</code> the deep comparison of
961      * two <code>boolean</code> arrays.</p>
962      *
963      * <ol>
964      *  <li>Check if arrays are the same using <code>==</code></li>
965      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
966      *  <li>Check array length, a shorter length array is less than a longer length array</li>
967      *  <li>Check array contents element by element using {@link #append(boolean, boolean)}</li>
968      * </ol>
969      *
970      * @param lhs  left-hand array
971      * @param rhs  right-hand array
972      * @return this - used to chain append calls
973      */
974     public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) {
975         if (comparison != 0) {
976             return this;
977         }
978         if (lhs == rhs) {
979             return this;
980         }
981         if (lhs == null) {
982             comparison = -1;
983             return this;
984         }
985         if (rhs == null) {
986             comparison = +1;
987             return this;
988         }
989         if (lhs.length != rhs.length) {
990             comparison = (lhs.length < rhs.length) ? -1 : +1;
991             return this;
992         }
993         for (int i = 0; i < lhs.length && comparison == 0; i++) {
994             append(lhs[i], rhs[i]);
995         }
996         return this;
997     }
998 
999     //-----------------------------------------------------------------------
1000     /**
1001      * Returns a negative integer, a positive integer, or zero as
1002      * the <code>builder</code> has judged the "left-hand" side
1003      * as less than, greater than, or equal to the "right-hand"
1004      * side.
1005      * 
1006      * @return final comparison result
1007      * @see #build()
1008      */
1009     public int toComparison() {
1010         return comparison;
1011     }
1012 
1013     /**
1014      * Returns a negative Integer, a positive Integer, or zero as
1015      * the <code>builder</code> has judged the "left-hand" side
1016      * as less than, greater than, or equal to the "right-hand"
1017      * side.
1018      * 
1019      * @return final comparison result as an Integer
1020      * @see #toComparison()
1021      * @since 3.0
1022      */
1023     @Override
1024     public Integer build() {
1025         return Integer.valueOf(toComparison());
1026     }
1027 }
1028