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