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 * https://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 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 side object
104 * @param rhs right-hand side 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 side object
151 * @param rhs right-hand side 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 side object
182 * @param rhs right-hand side 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 side object
215 * @param rhs right-hand side 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 side object
272 * @param rhs right-hand side 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 side object
305 * @param rhs right-hand side 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 side value
340 * @param rhs right-hand side value
341 * @return {@code this} instance.
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 side array
370 * @param rhs right-hand side array
371 * @return {@code this} instance.
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 side value
403 * @param rhs right-hand side value
404 * @return {@code this} instance.
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 side array
426 * @param rhs right-hand side array
427 * @return {@code this} instance.
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 side value
459 * @param rhs right-hand side value
460 * @return {@code this} instance.
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 side array
482 * @param rhs right-hand side array
483 * @return {@code this} instance.
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 side value
520 * @param rhs right-hand side value
521 * @return {@code this} instance.
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 side array
543 * @param rhs right-hand side array
544 * @return {@code this} instance.
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 side value
581 * @param rhs right-hand side value
582 * @return {@code this} instance.
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 side array
604 * @param rhs right-hand side array
605 * @return {@code this} instance.
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 side value
637 * @param rhs right-hand side value
638 * @return {@code this} instance.
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 side array
660 * @param rhs right-hand side array
661 * @return {@code this} instance.
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 side value
693 * @param rhs right-hand side value
694 * @return {@code this} instance.
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 side array
716 * @param rhs right-hand side array
717 * @return {@code this} instance.
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 side object
758 * @param rhs right-hand side object
759 * @return {@code this} instance.
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 side object
784 * @param rhs right-hand side object
785 * @param comparator {@link Comparator} used to compare the objects,
786 * {@code null} means treat lhs as {@link Comparable}
787 * @return {@code this} instance.
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 side array
838 * @param rhs right-hand side array
839 * @return {@code this} instance.
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 side array
862 * @param rhs right-hand side 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 {@code this} instance.
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 side value
900 * @param rhs right-hand side value
901 * @return {@code this} instance.
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 side array
923 * @param rhs right-hand side array
924 * @return {@code this} instance.
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 {@code this} instance.
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