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.lang3.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.lang3.ArrayUtils;
026    
027    /** 
028     * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods.
029     *
030     * 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     * @author Apache Software Foundation
086     * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
087     * @author Gary Gregory
088     * @author Pete Gieser
089     * @since 1.0
090     * @version $Id: CompareToBuilder.java 965941 2010-07-20 18:10:34Z bayard $
091     */
092    public class CompareToBuilder implements Builder<Integer> {
093        
094        /**
095         * Current state of the comparison as appended fields are checked.
096         */
097        private int comparison;
098    
099        /**
100         * <p>Constructor for CompareToBuilder.</p>
101         *
102         * <p>Starts off assuming that the objects are equal. Multiple calls are 
103         * then made to the various append methods, followed by a call to 
104         * {@link #toComparison} to get the result.</p>
105         */
106        public CompareToBuilder() {
107            super();
108            comparison = 0;
109        }
110    
111        //-----------------------------------------------------------------------
112        /** 
113         * <p>Compares two <code>Object</code>s via reflection.</p>
114         *
115         * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
116         * is used to bypass normal access control checks. This will fail under a 
117         * security manager unless the appropriate permissions are set.</p>
118         *
119         * <ul>
120         * <li>Static fields will not be compared</li>
121         * <li>Transient members will be not be compared, as they are likely derived
122         *     fields</li>
123         * <li>Superclass fields will be compared</li>
124         * </ul>
125         *
126         * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
127         * they are considered equal.</p>
128         *
129         * @param lhs  left-hand object
130         * @param rhs  right-hand object
131         * @return a negative integer, zero, or a positive integer as <code>lhs</code>
132         *  is less than, equal to, or greater than <code>rhs</code>
133         * @throws NullPointerException  if either (but not both) parameters are
134         *  <code>null</code>
135         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
136         *  with <code>lhs</code>
137         */
138        public static int reflectionCompare(Object lhs, Object rhs) {
139            return reflectionCompare(lhs, rhs, false, null, null);
140        }
141    
142        /**
143         * <p>Compares two <code>Object</code>s via reflection.</p>
144         *
145         * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
146         * is used to bypass normal access control checks. This will fail under a 
147         * security manager unless the appropriate permissions are set.</p>
148         *
149         * <ul>
150         * <li>Static fields will not be compared</li>
151         * <li>If <code>compareTransients</code> is <code>true</code>,
152         *     compares transient members.  Otherwise ignores them, as they
153         *     are likely derived fields.</li>
154         * <li>Superclass fields will be compared</li>
155         * </ul>
156         *
157         * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
158         * they are considered equal.</p>
159         *
160         * @param lhs  left-hand object
161         * @param rhs  right-hand object
162         * @param compareTransients  whether to compare transient fields
163         * @return a negative integer, zero, or a positive integer as <code>lhs</code>
164         *  is less than, equal to, or greater than <code>rhs</code>
165         * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
166         *  (but not both) is <code>null</code>
167         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
168         *  with <code>lhs</code>
169         */
170        public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) {
171            return reflectionCompare(lhs, rhs, compareTransients, null, null);
172        }
173    
174        /**
175         * <p>Compares two <code>Object</code>s via reflection.</p>
176         *
177         * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
178         * is used to bypass normal access control checks. This will fail under a 
179         * security manager unless the appropriate permissions are set.</p>
180         *
181         * <ul>
182         * <li>Static fields will not be compared</li>
183         * <li>If <code>compareTransients</code> is <code>true</code>,
184         *     compares transient members.  Otherwise ignores them, as they
185         *     are likely derived fields.</li>
186         * <li>Superclass fields will be compared</li>
187         * </ul>
188         *
189         * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
190         * they are considered equal.</p>
191         *
192         * @param lhs  left-hand object
193         * @param rhs  right-hand object
194         * @param excludeFields  Collection of String fields to exclude
195         * @return a negative integer, zero, or a positive integer as <code>lhs</code>
196         *  is less than, equal to, or greater than <code>rhs</code>
197         * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
198         *  (but not both) is <code>null</code>
199         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
200         *  with <code>lhs</code>
201         * @since 2.2
202         */
203        public static int reflectionCompare(Object lhs, Object rhs, Collection<String> excludeFields) {
204            return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
205        }
206    
207        /**
208         * <p>Compares two <code>Object</code>s via reflection.</p>
209         *
210         * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
211         * is used to bypass normal access control checks. This will fail under a 
212         * security manager unless the appropriate permissions are set.</p>
213         *
214         * <ul>
215         * <li>Static fields will not be compared</li>
216         * <li>If <code>compareTransients</code> is <code>true</code>,
217         *     compares transient members.  Otherwise ignores them, as they
218         *     are likely derived fields.</li>
219         * <li>Superclass fields will be compared</li>
220         * </ul>
221         *
222         * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
223         * they are considered equal.</p>
224         *
225         * @param lhs  left-hand object
226         * @param rhs  right-hand object
227         * @param excludeFields  array of fields to exclude
228         * @return a negative integer, zero, or a positive integer as <code>lhs</code>
229         *  is less than, equal to, or greater than <code>rhs</code>
230         * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
231         *  (but not both) is <code>null</code>
232         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
233         *  with <code>lhs</code>
234         * @since 2.2
235         */
236        public static int reflectionCompare(Object lhs, Object rhs, String[] excludeFields) {
237            return reflectionCompare(lhs, rhs, false, null, excludeFields);
238        }
239    
240        /**
241         * <p>Compares two <code>Object</code>s via reflection.</p>
242         *
243         * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
244         * is used to bypass normal access control checks. This will fail under a 
245         * security manager unless the appropriate permissions are set.</p>
246         *
247         * <ul>
248         * <li>Static fields will not be compared</li>
249         * <li>If the <code>compareTransients</code> is <code>true</code>,
250         *     compares transient members.  Otherwise ignores them, as they
251         *     are likely derived fields.</li>
252         * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
253         *     If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
254         * </ul>
255         *
256         * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
257         * they are considered equal.</p>
258         *
259         * @param lhs  left-hand object
260         * @param rhs  right-hand object
261         * @param compareTransients  whether to compare transient fields
262         * @param reflectUpToClass  last superclass for which fields are compared
263         * @return a negative integer, zero, or a positive integer as <code>lhs</code>
264         *  is less than, equal to, or greater than <code>rhs</code>
265         * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
266         *  (but not both) is <code>null</code>
267         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
268         *  with <code>lhs</code>
269         * @since 2.0
270         */
271        public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients, 
272                                            Class<?> reflectUpToClass) 
273        {
274            return reflectionCompare(lhs, rhs, compareTransients, reflectUpToClass, null);
275        }
276    
277        /**
278         * <p>Compares two <code>Object</code>s via reflection.</p>
279         *
280         * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
281         * is used to bypass normal access control checks. This will fail under a 
282         * security manager unless the appropriate permissions are set.</p>
283         *
284         * <ul>
285         * <li>Static fields will not be compared</li>
286         * <li>If the <code>compareTransients</code> is <code>true</code>,
287         *     compares transient members.  Otherwise ignores them, as they
288         *     are likely derived fields.</li>
289         * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
290         *     If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
291         * </ul>
292         *
293         * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
294         * they are considered equal.</p>
295         *
296         * @param lhs  left-hand object
297         * @param rhs  right-hand object
298         * @param compareTransients  whether to compare transient fields
299         * @param reflectUpToClass  last superclass for which fields are compared
300         * @param excludeFields  fields to exclude
301         * @return a negative integer, zero, or a positive integer as <code>lhs</code>
302         *  is less than, equal to, or greater than <code>rhs</code>
303         * @throws NullPointerException  if either <code>lhs</code> or <code>rhs</code>
304         *  (but not both) is <code>null</code>
305         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
306         *  with <code>lhs</code>
307         * @since 2.2
308         */
309        public static int reflectionCompare(
310            Object lhs, 
311            Object rhs, 
312            boolean compareTransients, 
313            Class<?> reflectUpToClass, 
314            String[] excludeFields) {
315    
316            if (lhs == rhs) {
317                return 0;
318            }
319            if (lhs == null || rhs == null) {
320                throw new NullPointerException();
321            }
322            Class<?> lhsClazz = lhs.getClass();
323            if (!lhsClazz.isInstance(rhs)) {
324                throw new ClassCastException();
325            }
326            CompareToBuilder compareToBuilder = new CompareToBuilder();
327            reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
328            while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
329                lhsClazz = lhsClazz.getSuperclass();
330                reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
331            }
332            return compareToBuilder.toComparison();
333        }
334    
335        /**
336         * <p>Appends to <code>builder</code> the comparison of <code>lhs</code>
337         * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
338         * 
339         * @param lhs  left-hand object
340         * @param rhs  right-hand object
341         * @param clazz  <code>Class</code> that defines fields to be compared
342         * @param builder  <code>CompareToBuilder</code> to append to
343         * @param useTransients  whether to compare transient fields
344         * @param excludeFields  fields to exclude
345         */
346        private static void reflectionAppend(
347            Object lhs,
348            Object rhs,
349            Class<?> clazz,
350            CompareToBuilder builder,
351            boolean useTransients,
352            String[] excludeFields) {
353            
354            Field[] fields = clazz.getDeclaredFields();
355            AccessibleObject.setAccessible(fields, true);
356            for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
357                Field f = fields[i];
358                if (!ArrayUtils.contains(excludeFields, f.getName())
359                    && (f.getName().indexOf('$') == -1)
360                    && (useTransients || !Modifier.isTransient(f.getModifiers()))
361                    && (!Modifier.isStatic(f.getModifiers()))) {
362                    try {
363                        builder.append(f.get(lhs), f.get(rhs));
364                    } catch (IllegalAccessException e) {
365                        // This can't happen. Would get a Security exception instead.
366                        // Throw a runtime exception in case the impossible happens.
367                        throw new InternalError("Unexpected IllegalAccessException");
368                    }
369                }
370            }
371        }
372    
373        //-----------------------------------------------------------------------
374        /**
375         * <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code>
376         * result of the superclass.</p>
377         *
378         * @param superCompareTo  result of calling <code>super.compareTo(Object)</code>
379         * @return this - used to chain append calls
380         * @since 2.0
381         */
382        public CompareToBuilder appendSuper(int superCompareTo) {
383            if (comparison != 0) {
384                return this;
385            }
386            comparison = superCompareTo;
387            return this;
388        }
389        
390        //-----------------------------------------------------------------------
391        /**
392         * <p>Appends to the <code>builder</code> the comparison of
393         * two <code>Object</code>s.</p>
394         *
395         * <ol>
396         * <li>Check if <code>lhs == rhs</code></li>
397         * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
398         *     a <code>null</code> object is less than a non-<code>null</code> object</li>
399         * <li>Check the object contents</li>
400         * </ol>
401         * 
402         * <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p>
403         *
404         * @param lhs  left-hand object
405         * @param rhs  right-hand object
406         * @return this - used to chain append calls
407         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
408         *  with <code>lhs</code>
409         */
410        public CompareToBuilder append(Object lhs, Object rhs) {
411            return append(lhs, rhs, null);
412        }
413    
414        /**
415         * <p>Appends to the <code>builder</code> the comparison of
416         * two <code>Object</code>s.</p>
417         *
418         * <ol>
419         * <li>Check if <code>lhs == rhs</code></li>
420         * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
421         *     a <code>null</code> object is less than a non-<code>null</code> object</li>
422         * <li>Check the object contents</li>
423         * </ol>
424         *
425         * <p>If <code>lhs</code> is an array, array comparison methods will be used.
426         * Otherwise <code>comparator</code> will be used to compare the objects.
427         * If <code>comparator</code> is <code>null</code>, <code>lhs</code> must
428         * implement {@link Comparable} instead.</p>
429         *
430         * @param lhs  left-hand object
431         * @param rhs  right-hand object
432         * @param comparator  <code>Comparator</code> used to compare the objects,
433         *  <code>null</code> means treat lhs as <code>Comparable</code>
434         * @return this - used to chain append calls
435         * @throws ClassCastException  if <code>rhs</code> is not assignment-compatible
436         *  with <code>lhs</code>
437         * @since 2.0
438         */
439        public CompareToBuilder append(Object lhs, Object rhs, Comparator<?> comparator) {
440            if (comparison != 0) {
441                return this;
442            }
443            if (lhs == rhs) {
444                return this;
445            }
446            if (lhs == null) {
447                comparison = -1;
448                return this;
449            }
450            if (rhs == null) {
451                comparison = +1;
452                return this;
453            }
454            if (lhs.getClass().isArray()) {
455                // switch on type of array, to dispatch to the correct handler
456                // handles multi dimensional arrays
457                // throws a ClassCastException if rhs is not the correct array type
458                if (lhs instanceof long[]) {
459                    append((long[]) lhs, (long[]) rhs);
460                } else if (lhs instanceof int[]) {
461                    append((int[]) lhs, (int[]) rhs);
462                } else if (lhs instanceof short[]) {
463                    append((short[]) lhs, (short[]) rhs);
464                } else if (lhs instanceof char[]) {
465                    append((char[]) lhs, (char[]) rhs);
466                } else if (lhs instanceof byte[]) {
467                    append((byte[]) lhs, (byte[]) rhs);
468                } else if (lhs instanceof double[]) {
469                    append((double[]) lhs, (double[]) rhs);
470                } else if (lhs instanceof float[]) {
471                    append((float[]) lhs, (float[]) rhs);
472                } else if (lhs instanceof boolean[]) {
473                    append((boolean[]) lhs, (boolean[]) rhs);
474                } else {
475                    // not an array of primitives
476                    // throws a ClassCastException if rhs is not an array
477                    append((Object[]) lhs, (Object[]) rhs, comparator);
478                }
479            } else {
480                // the simple case, not an array, just test the element
481                if (comparator == null) {
482                    @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
483                    final Comparable<Object> comparable = (Comparable<Object>) lhs;
484                    comparison = comparable.compareTo(rhs);
485                } else {
486                    @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
487                    final Comparator<Object> comparator2 = (Comparator<Object>) comparator;
488                    comparison = comparator2.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 = Double.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 = Float.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         * Returns a negative integer, a positive integer, or zero as
1048         * the <code>builder</code> has judged the "left-hand" side
1049         * as less than, greater than, or equal to the "right-hand"
1050         * side.
1051         * 
1052         * @return final comparison result
1053         * 
1054         * @since 3.0
1055         */
1056        public Integer build() {
1057            return toComparison();
1058        }
1059    }
1060