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