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