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   * @version $Id: CompareToBuilder.java 1628165 2014-09-29 12:02:11Z djones $
95   */
96  public class CompareToBuilder implements Builder<Integer> {
97      
98      /**
99       * 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</code>s via reflection.</p>
118      *
119      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
136      *  is less than, equal to, or greater than <code>rhs</code>
137      * @throws NullPointerException  if either (but not both) parameters are
138      *  <code>null</code>
139      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
140      *  with <code>lhs</code>
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</code>s via reflection.</p>
148      *
149      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
168      *  is less than, equal to, or greater than <code>rhs</code>
169      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
170      *  (but not both) is <code>null</code>
171      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
172      *  with <code>lhs</code>
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</code>s via reflection.</p>
180      *
181      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
200      *  is less than, equal to, or greater than <code>rhs</code>
201      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
202      *  (but not both) is <code>null</code>
203      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
204      *  with <code>lhs</code>
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</code>s via reflection.</p>
213      *
214      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code> and <code>rhs</code> are <code>null</code>,
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</code>
233      *  is less than, equal to, or greater than <code>rhs</code>
234      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
235      *  (but not both) is <code>null</code>
236      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
237      *  with <code>lhs</code>
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</code>s via reflection.</p>
246      *
247      * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
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</code> is <code>true</code>,
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</code>.
257      *     If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
258      * </ul>
259      *
260      * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
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</code>
269      *  is less than, equal to, or greater than <code>rhs</code>
270      * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
271      *  (but not both) is <code>null</code>
272      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
273      *  with <code>lhs</code>
274      * @since 2.2 (2.0 as <code>reflectionCompare(Object, Object, boolean, Class)</code>)
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         if (lhs == null || rhs == null) {
287             throw new NullPointerException();
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</code> the comparison of <code>lhs</code>
304      * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
305      * 
306      * @param lhs  left-hand object
307      * @param rhs  right-hand object
308      * @param clazz  <code>Class</code> that defines fields to be compared
309      * @param builder  <code>CompareToBuilder</code> 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().indexOf('$') == -1)
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</code> the <code>compareTo(Object)</code>
343      * result of the superclass.</p>
344      *
345      * @param superCompareTo  result of calling <code>super.compareTo(Object)</code>
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</code> the comparison of
360      * two <code>Object</code>s.</p>
361      *
362      * <ol>
363      * <li>Check if <code>lhs == rhs</code></li>
364      * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
365      *     a <code>null</code> object is less than a non-<code>null</code> object</li>
366      * <li>Check the object contents</li>
367      * </ol>
368      * 
369      * <p><code>lhs</code> 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</code> is not assignment-compatible
375      *  with <code>lhs</code>
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</code> the comparison of
383      * two <code>Object</code>s.</p>
384      *
385      * <ol>
386      * <li>Check if <code>lhs == rhs</code></li>
387      * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
388      *     a <code>null</code> object is less than a non-<code>null</code> object</li>
389      * <li>Check the object contents</li>
390      * </ol>
391      *
392      * <p>If <code>lhs</code> is an array, array comparison methods will be used.
393      * Otherwise <code>comparator</code> will be used to compare the objects.
394      * If <code>comparator</code> is <code>null</code>, <code>lhs</code> 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</code> used to compare the objects,
400      *  <code>null</code> means treat lhs as <code>Comparable</code>
401      * @return this - used to chain append calls
402      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
403      *  with <code>lhs</code>
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             // switch on type of array, to dispatch to the correct handler
423             // handles multi dimensional arrays
424             // throws a ClassCastException if rhs is not the correct array type
425             if (lhs instanceof long[]) {
426                 append((long[]) lhs, (long[]) rhs);
427             } else if (lhs instanceof int[]) {
428                 append((int[]) lhs, (int[]) rhs);
429             } else if (lhs instanceof short[]) {
430                 append((short[]) lhs, (short[]) rhs);
431             } else if (lhs instanceof char[]) {
432                 append((char[]) lhs, (char[]) rhs);
433             } else if (lhs instanceof byte[]) {
434                 append((byte[]) lhs, (byte[]) rhs);
435             } else if (lhs instanceof double[]) {
436                 append((double[]) lhs, (double[]) rhs);
437             } else if (lhs instanceof float[]) {
438                 append((float[]) lhs, (float[]) rhs);
439             } else if (lhs instanceof boolean[]) {
440                 append((boolean[]) lhs, (boolean[]) rhs);
441             } else {
442                 // not an array of primitives
443                 // throws a ClassCastException if rhs is not an array
444                 append((Object[]) lhs, (Object[]) rhs, comparator);
445             }
446         } else {
447             // the simple case, not an array, just test the element
448             if (comparator == null) {
449                 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
450                 final Comparable<Object> comparable = (Comparable<Object>) lhs;
451                 comparison = comparable.compareTo(rhs);
452             } else {
453                 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
454                 final Comparator<Object> comparator2 = (Comparator<Object>) comparator;
455                 comparison = comparator2.compare(lhs, rhs);
456             }
457         }
458         return this;
459     }
460 
461     //-------------------------------------------------------------------------
462     /**
463      * Appends to the <code>builder</code> the comparison of
464      * two <code>long</code>s.
465      *
466      * @param lhs  left-hand value
467      * @param rhs  right-hand value
468      * @return this - used to chain append calls
469      */
470     public CompareToBuilder append(final long lhs, final long rhs) {
471         if (comparison != 0) {
472             return this;
473         }
474         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
475         return this;
476     }
477 
478     /**
479      * Appends to the <code>builder</code> the comparison of
480      * two <code>int</code>s.
481      *
482      * @param lhs  left-hand value
483      * @param rhs  right-hand value
484      * @return this - used to chain append calls
485      */
486     public CompareToBuilder append(final int lhs, final int rhs) {
487         if (comparison != 0) {
488             return this;
489         }
490         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
491         return this;
492     }
493 
494     /**
495      * Appends to the <code>builder</code> the comparison of
496      * two <code>short</code>s.
497      * 
498      * @param lhs  left-hand value
499      * @param rhs  right-hand value
500      * @return this - used to chain append calls
501      */
502     public CompareToBuilder append(final short lhs, final short rhs) {
503         if (comparison != 0) {
504             return this;
505         }
506         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
507         return this;
508     }
509 
510     /**
511      * Appends to the <code>builder</code> the comparison of
512      * two <code>char</code>s.
513      *
514      * @param lhs  left-hand value
515      * @param rhs  right-hand value
516      * @return this - used to chain append calls
517      */
518     public CompareToBuilder append(final char lhs, final char rhs) {
519         if (comparison != 0) {
520             return this;
521         }
522         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
523         return this;
524     }
525 
526     /**
527      * Appends to the <code>builder</code> the comparison of
528      * two <code>byte</code>s.
529      * 
530      * @param lhs  left-hand value
531      * @param rhs  right-hand value
532      * @return this - used to chain append calls
533      */
534     public CompareToBuilder append(final byte lhs, final byte rhs) {
535         if (comparison != 0) {
536             return this;
537         }
538         comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
539         return this;
540     }
541 
542     /**
543      * <p>Appends to the <code>builder</code> the comparison of
544      * two <code>double</code>s.</p>
545      *
546      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
547      *
548      * <p>It is compatible with the hash code generated by
549      * <code>HashCodeBuilder</code>.</p>
550      *
551      * @param lhs  left-hand value
552      * @param rhs  right-hand value
553      * @return this - used to chain append calls
554      */
555     public CompareToBuilder append(final double lhs, final double rhs) {
556         if (comparison != 0) {
557             return this;
558         }
559         comparison = Double.compare(lhs, rhs);
560         return this;
561     }
562 
563     /**
564      * <p>Appends to the <code>builder</code> the comparison of
565      * two <code>float</code>s.</p>
566      *
567      * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
568      *
569      * <p>It is compatible with the hash code generated by
570      * <code>HashCodeBuilder</code>.</p>
571      *
572      * @param lhs  left-hand value
573      * @param rhs  right-hand value
574      * @return this - used to chain append calls
575      */
576     public CompareToBuilder append(final float lhs, final float rhs) {
577         if (comparison != 0) {
578             return this;
579         }
580         comparison = Float.compare(lhs, rhs);
581         return this;
582     }
583 
584     /**
585      * Appends to the <code>builder</code> the comparison of
586      * two <code>booleans</code>s.
587      *
588      * @param lhs  left-hand value
589      * @param rhs  right-hand value
590      * @return this - used to chain append calls
591       */
592     public CompareToBuilder append(final boolean lhs, final boolean rhs) {
593         if (comparison != 0) {
594             return this;
595         }
596         if (lhs == rhs) {
597             return this;
598         }
599         if (lhs == false) {
600             comparison = -1;
601         } else {
602             comparison = +1;
603         }
604         return this;
605     }
606 
607     //-----------------------------------------------------------------------
608     /**
609      * <p>Appends to the <code>builder</code> the deep comparison of
610      * two <code>Object</code> arrays.</p>
611      *
612      * <ol>
613      *  <li>Check if arrays are the same using <code>==</code></li>
614      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
615      *  <li>Check array length, a short length array is less than a long length array</li>
616      *  <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
617      * </ol>
618      *
619      * <p>This method will also will be called for the top level of multi-dimensional,
620      * ragged, and multi-typed arrays.</p>
621      *
622      * @param lhs  left-hand array
623      * @param rhs  right-hand array
624      * @return this - used to chain append calls
625      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
626      *  with <code>lhs</code>
627      */
628     public CompareToBuilder append(final Object[] lhs, final Object[] rhs) {
629         return append(lhs, rhs, null);
630     }
631     
632     /**
633      * <p>Appends to the <code>builder</code> the deep comparison of
634      * two <code>Object</code> arrays.</p>
635      *
636      * <ol>
637      *  <li>Check if arrays are the same using <code>==</code></li>
638      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
639      *  <li>Check array length, a short length array is less than a long length array</li>
640      *  <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
641      * </ol>
642      *
643      * <p>This method will also will be called for the top level of multi-dimensional,
644      * ragged, and multi-typed arrays.</p>
645      *
646      * @param lhs  left-hand array
647      * @param rhs  right-hand array
648      * @param comparator  <code>Comparator</code> to use to compare the array elements,
649      *  <code>null</code> means to treat <code>lhs</code> elements as <code>Comparable</code>.
650      * @return this - used to chain append calls
651      * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
652      *  with <code>lhs</code>
653      * @since 2.0
654      */
655     public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator<?> comparator) {
656         if (comparison != 0) {
657             return this;
658         }
659         if (lhs == rhs) {
660             return this;
661         }
662         if (lhs == null) {
663             comparison = -1;
664             return this;
665         }
666         if (rhs == null) {
667             comparison = +1;
668             return this;
669         }
670         if (lhs.length != rhs.length) {
671             comparison = (lhs.length < rhs.length) ? -1 : +1;
672             return this;
673         }
674         for (int i = 0; i < lhs.length && comparison == 0; i++) {
675             append(lhs[i], rhs[i], comparator);
676         }
677         return this;
678     }
679 
680     /**
681      * <p>Appends to the <code>builder</code> the deep comparison of
682      * two <code>long</code> arrays.</p>
683      *
684      * <ol>
685      *  <li>Check if arrays are the same using <code>==</code></li>
686      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
687      *  <li>Check array length, a shorter length array is less than a longer length array</li>
688      *  <li>Check array contents element by element using {@link #append(long, long)}</li>
689      * </ol>
690      *
691      * @param lhs  left-hand array
692      * @param rhs  right-hand array
693      * @return this - used to chain append calls
694      */
695     public CompareToBuilder append(final long[] lhs, final long[] rhs) {
696         if (comparison != 0) {
697             return this;
698         }
699         if (lhs == rhs) {
700             return this;
701         }
702         if (lhs == null) {
703             comparison = -1;
704             return this;
705         }
706         if (rhs == null) {
707             comparison = +1;
708             return this;
709         }
710         if (lhs.length != rhs.length) {
711             comparison = (lhs.length < rhs.length) ? -1 : +1;
712             return this;
713         }
714         for (int i = 0; i < lhs.length && comparison == 0; i++) {
715             append(lhs[i], rhs[i]);
716         }
717         return this;
718     }
719 
720     /**
721      * <p>Appends to the <code>builder</code> the deep comparison of
722      * two <code>int</code> arrays.</p>
723      *
724      * <ol>
725      *  <li>Check if arrays are the same using <code>==</code></li>
726      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
727      *  <li>Check array length, a shorter length array is less than a longer length array</li>
728      *  <li>Check array contents element by element using {@link #append(int, int)}</li>
729      * </ol>
730      *
731      * @param lhs  left-hand array
732      * @param rhs  right-hand array
733      * @return this - used to chain append calls
734      */
735     public CompareToBuilder append(final int[] lhs, final int[] rhs) {
736         if (comparison != 0) {
737             return this;
738         }
739         if (lhs == rhs) {
740             return this;
741         }
742         if (lhs == null) {
743             comparison = -1;
744             return this;
745         }
746         if (rhs == null) {
747             comparison = +1;
748             return this;
749         }
750         if (lhs.length != rhs.length) {
751             comparison = (lhs.length < rhs.length) ? -1 : +1;
752             return this;
753         }
754         for (int i = 0; i < lhs.length && comparison == 0; i++) {
755             append(lhs[i], rhs[i]);
756         }
757         return this;
758     }
759 
760     /**
761      * <p>Appends to the <code>builder</code> the deep comparison of
762      * two <code>short</code> arrays.</p>
763      *
764      * <ol>
765      *  <li>Check if arrays are the same using <code>==</code></li>
766      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
767      *  <li>Check array length, a shorter length array is less than a longer length array</li>
768      *  <li>Check array contents element by element using {@link #append(short, short)}</li>
769      * </ol>
770      *
771      * @param lhs  left-hand array
772      * @param rhs  right-hand array
773      * @return this - used to chain append calls
774      */
775     public CompareToBuilder append(final short[] lhs, final short[] rhs) {
776         if (comparison != 0) {
777             return this;
778         }
779         if (lhs == rhs) {
780             return this;
781         }
782         if (lhs == null) {
783             comparison = -1;
784             return this;
785         }
786         if (rhs == null) {
787             comparison = +1;
788             return this;
789         }
790         if (lhs.length != rhs.length) {
791             comparison = (lhs.length < rhs.length) ? -1 : +1;
792             return this;
793         }
794         for (int i = 0; i < lhs.length && comparison == 0; i++) {
795             append(lhs[i], rhs[i]);
796         }
797         return this;
798     }
799 
800     /**
801      * <p>Appends to the <code>builder</code> the deep comparison of
802      * two <code>char</code> arrays.</p>
803      *
804      * <ol>
805      *  <li>Check if arrays are the same using <code>==</code></li>
806      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
807      *  <li>Check array length, a shorter length array is less than a longer length array</li>
808      *  <li>Check array contents element by element using {@link #append(char, char)}</li>
809      * </ol>
810      *
811      * @param lhs  left-hand array
812      * @param rhs  right-hand array
813      * @return this - used to chain append calls
814      */
815     public CompareToBuilder append(final char[] lhs, final char[] rhs) {
816         if (comparison != 0) {
817             return this;
818         }
819         if (lhs == rhs) {
820             return this;
821         }
822         if (lhs == null) {
823             comparison = -1;
824             return this;
825         }
826         if (rhs == null) {
827             comparison = +1;
828             return this;
829         }
830         if (lhs.length != rhs.length) {
831             comparison = (lhs.length < rhs.length) ? -1 : +1;
832             return this;
833         }
834         for (int i = 0; i < lhs.length && comparison == 0; i++) {
835             append(lhs[i], rhs[i]);
836         }
837         return this;
838     }
839 
840     /**
841      * <p>Appends to the <code>builder</code> the deep comparison of
842      * two <code>byte</code> arrays.</p>
843      *
844      * <ol>
845      *  <li>Check if arrays are the same using <code>==</code></li>
846      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
847      *  <li>Check array length, a shorter length array is less than a longer length array</li>
848      *  <li>Check array contents element by element using {@link #append(byte, byte)}</li>
849      * </ol>
850      *
851      * @param lhs  left-hand array
852      * @param rhs  right-hand array
853      * @return this - used to chain append calls
854      */
855     public CompareToBuilder append(final byte[] lhs, final byte[] rhs) {
856         if (comparison != 0) {
857             return this;
858         }
859         if (lhs == rhs) {
860             return this;
861         }
862         if (lhs == null) {
863             comparison = -1;
864             return this;
865         }
866         if (rhs == null) {
867             comparison = +1;
868             return this;
869         }
870         if (lhs.length != rhs.length) {
871             comparison = (lhs.length < rhs.length) ? -1 : +1;
872             return this;
873         }
874         for (int i = 0; i < lhs.length && comparison == 0; i++) {
875             append(lhs[i], rhs[i]);
876         }
877         return this;
878     }
879 
880     /**
881      * <p>Appends to the <code>builder</code> the deep comparison of
882      * two <code>double</code> arrays.</p>
883      *
884      * <ol>
885      *  <li>Check if arrays are the same using <code>==</code></li>
886      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
887      *  <li>Check array length, a shorter length array is less than a longer length array</li>
888      *  <li>Check array contents element by element using {@link #append(double, double)}</li>
889      * </ol>
890      *
891      * @param lhs  left-hand array
892      * @param rhs  right-hand array
893      * @return this - used to chain append calls
894      */
895     public CompareToBuilder append(final double[] lhs, final double[] rhs) {
896         if (comparison != 0) {
897             return this;
898         }
899         if (lhs == rhs) {
900             return this;
901         }
902         if (lhs == null) {
903             comparison = -1;
904             return this;
905         }
906         if (rhs == null) {
907             comparison = +1;
908             return this;
909         }
910         if (lhs.length != rhs.length) {
911             comparison = (lhs.length < rhs.length) ? -1 : +1;
912             return this;
913         }
914         for (int i = 0; i < lhs.length && comparison == 0; i++) {
915             append(lhs[i], rhs[i]);
916         }
917         return this;
918     }
919 
920     /**
921      * <p>Appends to the <code>builder</code> the deep comparison of
922      * two <code>float</code> arrays.</p>
923      *
924      * <ol>
925      *  <li>Check if arrays are the same using <code>==</code></li>
926      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
927      *  <li>Check array length, a shorter length array is less than a longer length array</li>
928      *  <li>Check array contents element by element using {@link #append(float, float)}</li>
929      * </ol>
930      *
931      * @param lhs  left-hand array
932      * @param rhs  right-hand array
933      * @return this - used to chain append calls
934      */
935     public CompareToBuilder append(final float[] lhs, final float[] rhs) {
936         if (comparison != 0) {
937             return this;
938         }
939         if (lhs == rhs) {
940             return this;
941         }
942         if (lhs == null) {
943             comparison = -1;
944             return this;
945         }
946         if (rhs == null) {
947             comparison = +1;
948             return this;
949         }
950         if (lhs.length != rhs.length) {
951             comparison = (lhs.length < rhs.length) ? -1 : +1;
952             return this;
953         }
954         for (int i = 0; i < lhs.length && comparison == 0; i++) {
955             append(lhs[i], rhs[i]);
956         }
957         return this;
958     }
959 
960     /**
961      * <p>Appends to the <code>builder</code> the deep comparison of
962      * two <code>boolean</code> arrays.</p>
963      *
964      * <ol>
965      *  <li>Check if arrays are the same using <code>==</code></li>
966      *  <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
967      *  <li>Check array length, a shorter length array is less than a longer length array</li>
968      *  <li>Check array contents element by element using {@link #append(boolean, boolean)}</li>
969      * </ol>
970      *
971      * @param lhs  left-hand array
972      * @param rhs  right-hand array
973      * @return this - used to chain append calls
974      */
975     public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) {
976         if (comparison != 0) {
977             return this;
978         }
979         if (lhs == rhs) {
980             return this;
981         }
982         if (lhs == null) {
983             comparison = -1;
984             return this;
985         }
986         if (rhs == null) {
987             comparison = +1;
988             return this;
989         }
990         if (lhs.length != rhs.length) {
991             comparison = (lhs.length < rhs.length) ? -1 : +1;
992             return this;
993         }
994         for (int i = 0; i < lhs.length && comparison == 0; i++) {
995             append(lhs[i], rhs[i]);
996         }
997         return this;
998     }
999 
1000     //-----------------------------------------------------------------------
1001     /**
1002      * Returns a negative integer, a positive integer, or zero as
1003      * the <code>builder</code> has judged the "left-hand" side
1004      * as less than, greater than, or equal to the "right-hand"
1005      * side.
1006      * 
1007      * @return final comparison result
1008      * @see #build()
1009      */
1010     public int toComparison() {
1011         return comparison;
1012     }
1013 
1014     /**
1015      * Returns a negative Integer, a positive Integer, or zero as
1016      * the <code>builder</code> has judged the "left-hand" side
1017      * as less than, greater than, or equal to the "right-hand"
1018      * side.
1019      * 
1020      * @return final comparison result as an Integer
1021      * @see #toComparison()
1022      * @since 3.0
1023      */
1024     @Override
1025     public Integer build() {
1026         return Integer.valueOf(toComparison());
1027     }
1028 }
1029