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