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