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