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.lang.builder;
018
019 import java.lang.reflect.AccessibleObject;
020 import java.lang.reflect.Field;
021 import java.lang.reflect.Modifier;
022 import java.util.Arrays;
023 import java.util.Collection;
024 import java.util.Collections;
025 import java.util.Comparator;
026 import java.util.List;
027
028 import org.apache.commons.lang.math.NumberUtils;
029
030 /**
031 * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods.
032 *
033 * It is consistent with <code>equals(Object)</code> and
034 * <code>hashcode()</code> built with {@link EqualsBuilder} and
035 * {@link HashCodeBuilder}.</p>
036 *
037 * <p>Two Objects that compare equal using <code>equals(Object)</code> should normally
038 * also compare equal using <code>compareTo(Object)</code>.</p>
039 *
040 * <p>All relevant fields should be included in the calculation of the
041 * comparison. Derived fields may be ignored. The same fields, in the same
042 * order, should be used in both <code>compareTo(Object)</code> and
043 * <code>equals(Object)</code>.</p>
044 *
045 * <p>To use this class write code as follows:</p>
046 *
047 * <pre>
048 * public class MyClass {
049 * String field1;
050 * int field2;
051 * boolean field3;
052 *
053 * ...
054 *
055 * public int compareTo(Object o) {
056 * MyClass myClass = (MyClass) o;
057 * return new CompareToBuilder()
058 * .appendSuper(super.compareTo(o)
059 * .append(this.field1, myClass.field1)
060 * .append(this.field2, myClass.field2)
061 * .append(this.field3, myClass.field3)
062 * .toComparison();
063 * }
064 * }
065 * </pre>
066 *
067 * <p>Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
068 * reflection to determine the fields to append. Because fields can be private,
069 * <code>reflectionCompare</code> uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
070 * bypass normal access control checks. This will fail under a security manager,
071 * unless the appropriate permissions are set up correctly. It is also
072 * slower than appending explicitly.</p>
073 *
074 * <p>A typical implementation of <code>compareTo(Object)</code> using
075 * <code>reflectionCompare</code> looks like:</p>
076
077 * <pre>
078 * public int compareTo(Object o) {
079 * return CompareToBuilder.reflectionCompare(this, o);
080 * }
081 * </pre>
082 *
083 * @see java.lang.Comparable
084 * @see java.lang.Object#equals(Object)
085 * @see java.lang.Object#hashCode()
086 * @see EqualsBuilder
087 * @see HashCodeBuilder
088 * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
089 * @author Stephen Colebourne
090 * @author Gary Gregory
091 * @author Pete Gieser
092 * @since 1.0
093 * @version $Id: CompareToBuilder.java 583666 2007-10-11 01:38:13Z ggregory $
094 */
095 public class CompareToBuilder {
096
097 /**
098 * Current state of the comparison as appended fields are checked.
099 */
100 private int comparison;
101
102 /**
103 * <p>Constructor for CompareToBuilder.</p>
104 *
105 * <p>Starts off assuming that the objects are equal. Multiple calls are
106 * then made to the various append methods, followed by a call to
107 * {@link #toComparison} to get the result.</p>
108 */
109 public CompareToBuilder() {
110 super();
111 comparison = 0;
112 }
113
114 //-----------------------------------------------------------------------
115 /**
116 * <p>Compares two <code>Object</code>s via reflection.</p>
117 *
118 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
119 * is used to bypass normal access control checks. This will fail under a
120 * security manager unless the appropriate permissions are set.</p>
121 *
122 * <ul>
123 * <li>Static fields will not be compared</li>
124 * <li>Transient members will be not be compared, as they are likely derived
125 * fields</li>
126 * <li>Superclass fields will be compared</li>
127 * </ul>
128 *
129 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
130 * they are considered equal.</p>
131 *
132 * @param lhs left-hand object
133 * @param rhs right-hand object
134 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
135 * is less than, equal to, or greater than <code>rhs</code>
136 * @throws NullPointerException if either (but not both) parameters are
137 * <code>null</code>
138 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
139 * with <code>lhs</code>
140 */
141 public static int reflectionCompare(Object lhs, Object rhs) {
142 return reflectionCompare(lhs, rhs, false, null, null);
143 }
144
145 /**
146 * <p>Compares two <code>Object</code>s via reflection.</p>
147 *
148 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
149 * is used to bypass normal access control checks. This will fail under a
150 * security manager unless the appropriate permissions are set.</p>
151 *
152 * <ul>
153 * <li>Static fields will not be compared</li>
154 * <li>If <code>compareTransients</code> is <code>true</code>,
155 * compares transient members. Otherwise ignores them, as they
156 * are likely derived fields.</li>
157 * <li>Superclass fields will be compared</li>
158 * </ul>
159 *
160 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
161 * they are considered equal.</p>
162 *
163 * @param lhs left-hand object
164 * @param rhs right-hand object
165 * @param compareTransients whether to compare transient fields
166 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
167 * is less than, equal to, or greater than <code>rhs</code>
168 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
169 * (but not both) is <code>null</code>
170 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
171 * with <code>lhs</code>
172 */
173 public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) {
174 return reflectionCompare(lhs, rhs, compareTransients, null, null);
175 }
176
177 /**
178 * <p>Compares two <code>Object</code>s via reflection.</p>
179 *
180 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
181 * is used to bypass normal access control checks. This will fail under a
182 * security manager unless the appropriate permissions are set.</p>
183 *
184 * <ul>
185 * <li>Static fields will not be compared</li>
186 * <li>If <code>compareTransients</code> is <code>true</code>,
187 * compares transient members. Otherwise ignores them, as they
188 * are likely derived fields.</li>
189 * <li>Superclass fields will be compared</li>
190 * </ul>
191 *
192 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
193 * they are considered equal.</p>
194 *
195 * @param lhs left-hand object
196 * @param rhs right-hand object
197 * @param excludeFields Collection of String fields to exclude
198 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
199 * is less than, equal to, or greater than <code>rhs</code>
200 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
201 * (but not both) is <code>null</code>
202 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
203 * with <code>lhs</code>
204 * @since 2.2
205 */
206 public static int reflectionCompare(Object lhs, Object rhs, Collection /*String*/ excludeFields) {
207 return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
208 }
209
210 /**
211 * <p>Compares two <code>Object</code>s via reflection.</p>
212 *
213 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
214 * is used to bypass normal access control checks. This will fail under a
215 * security manager unless the appropriate permissions are set.</p>
216 *
217 * <ul>
218 * <li>Static fields will not be compared</li>
219 * <li>If <code>compareTransients</code> is <code>true</code>,
220 * compares transient members. Otherwise ignores them, as they
221 * are likely derived fields.</li>
222 * <li>Superclass fields will be compared</li>
223 * </ul>
224 *
225 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
226 * they are considered equal.</p>
227 *
228 * @param lhs left-hand object
229 * @param rhs right-hand object
230 * @param excludeFields array of fields to exclude
231 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
232 * is less than, equal to, or greater than <code>rhs</code>
233 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
234 * (but not both) is <code>null</code>
235 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
236 * with <code>lhs</code>
237 * @since 2.2
238 */
239 public static int reflectionCompare(Object lhs, Object rhs, String[] excludeFields) {
240 return reflectionCompare(lhs, rhs, false, null, excludeFields);
241 }
242
243 /**
244 * <p>Compares two <code>Object</code>s via reflection.</p>
245 *
246 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
247 * is used to bypass normal access control checks. This will fail under a
248 * security manager unless the appropriate permissions are set.</p>
249 *
250 * <ul>
251 * <li>Static fields will not be compared</li>
252 * <li>If the <code>compareTransients</code> is <code>true</code>,
253 * compares transient members. Otherwise ignores them, as they
254 * are likely derived fields.</li>
255 * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
256 * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
257 * </ul>
258 *
259 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
260 * they are considered equal.</p>
261 *
262 * @param lhs left-hand object
263 * @param rhs right-hand object
264 * @param compareTransients whether to compare transient fields
265 * @param reflectUpToClass last superclass for which fields are compared
266 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
267 * is less than, equal to, or greater than <code>rhs</code>
268 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
269 * (but not both) is <code>null</code>
270 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
271 * with <code>lhs</code>
272 * @since 2.0
273 */
274 public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients,
275 Class reflectUpToClass)
276 {
277 return reflectionCompare(lhs, rhs, false, reflectUpToClass, null);
278 }
279
280 /**
281 * <p>Compares two <code>Object</code>s via reflection.</p>
282 *
283 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
284 * is used to bypass normal access control checks. This will fail under a
285 * security manager unless the appropriate permissions are set.</p>
286 *
287 * <ul>
288 * <li>Static fields will not be compared</li>
289 * <li>If the <code>compareTransients</code> is <code>true</code>,
290 * compares transient members. Otherwise ignores them, as they
291 * are likely derived fields.</li>
292 * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
293 * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
294 * </ul>
295 *
296 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
297 * they are considered equal.</p>
298 *
299 * @param lhs left-hand object
300 * @param rhs right-hand object
301 * @param compareTransients whether to compare transient fields
302 * @param reflectUpToClass last superclass for which fields are compared
303 * @param excludeFields fields to exclude
304 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
305 * is less than, equal to, or greater than <code>rhs</code>
306 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
307 * (but not both) is <code>null</code>
308 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
309 * with <code>lhs</code>
310 * @since 2.2
311 */
312 public static int reflectionCompare(
313 Object lhs,
314 Object rhs,
315 boolean compareTransients,
316 Class reflectUpToClass,
317 String[] excludeFields) {
318
319 if (lhs == rhs) {
320 return 0;
321 }
322 if (lhs == null || rhs == null) {
323 throw new NullPointerException();
324 }
325 Class lhsClazz = lhs.getClass();
326 if (!lhsClazz.isInstance(rhs)) {
327 throw new ClassCastException();
328 }
329 CompareToBuilder compareToBuilder = new CompareToBuilder();
330 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
331 while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
332 lhsClazz = lhsClazz.getSuperclass();
333 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
334 }
335 return compareToBuilder.toComparison();
336 }
337
338 /**
339 * <p>Appends to <code>builder</code> the comparison of <code>lhs</code>
340 * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
341 *
342 * @param lhs left-hand object
343 * @param rhs right-hand object
344 * @param clazz <code>Class</code> that defines fields to be compared
345 * @param builder <code>CompareToBuilder</code> to append to
346 * @param useTransients whether to compare transient fields
347 * @param excludeFields fields to exclude
348 */
349 private static void reflectionAppend(
350 Object lhs,
351 Object rhs,
352 Class clazz,
353 CompareToBuilder builder,
354 boolean useTransients,
355 String[] excludeFields) {
356
357 Field[] fields = clazz.getDeclaredFields();
358 List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) : Collections.EMPTY_LIST;
359 AccessibleObject.setAccessible(fields, true);
360 for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
361 Field f = fields[i];
362 if (!excludedFieldList.contains(f.getName())
363 && (f.getName().indexOf('$') == -1)
364 && (useTransients || !Modifier.isTransient(f.getModifiers()))
365 && (!Modifier.isStatic(f.getModifiers()))) {
366 try {
367 builder.append(f.get(lhs), f.get(rhs));
368 } catch (IllegalAccessException e) {
369 // This can't happen. Would get a Security exception instead.
370 // Throw a runtime exception in case the impossible happens.
371 throw new InternalError("Unexpected IllegalAccessException");
372 }
373 }
374 }
375 }
376
377 //-----------------------------------------------------------------------
378 /**
379 * <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code>
380 * result of the superclass.</p>
381 *
382 * @param superCompareTo result of calling <code>super.compareTo(Object)</code>
383 * @return this - used to chain append calls
384 * @since 2.0
385 */
386 public CompareToBuilder appendSuper(int superCompareTo) {
387 if (comparison != 0) {
388 return this;
389 }
390 comparison = superCompareTo;
391 return this;
392 }
393
394 //-----------------------------------------------------------------------
395 /**
396 * <p>Appends to the <code>builder</code> the comparison of
397 * two <code>Object</code>s.</p>
398 *
399 * <ol>
400 * <li>Check if <code>lhs == rhs</code></li>
401 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
402 * a <code>null</code> object is less than a non-<code>null</code> object</li>
403 * <li>Check the object contents</li>
404 * </ol>
405 *
406 * <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p>
407 *
408 * @param lhs left-hand object
409 * @param rhs right-hand object
410 * @return this - used to chain append calls
411 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
412 * with <code>lhs</code>
413 */
414 public CompareToBuilder append(Object lhs, Object rhs) {
415 return append(lhs, rhs, null);
416 }
417
418 /**
419 * <p>Appends to the <code>builder</code> the comparison of
420 * two <code>Object</code>s.</p>
421 *
422 * <ol>
423 * <li>Check if <code>lhs == rhs</code></li>
424 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
425 * a <code>null</code> object is less than a non-<code>null</code> object</li>
426 * <li>Check the object contents</li>
427 * </ol>
428 *
429 * <p>If <code>lhs</code> is an array, array comparison methods will be used.
430 * Otherwise <code>comparator</code> will be used to compare the objects.
431 * If <code>comparator</code> is <code>null</code>, <code>lhs</code> must
432 * implement {@link Comparable} instead.</p>
433 *
434 * @param lhs left-hand object
435 * @param rhs right-hand object
436 * @param comparator <code>Comparator</code> used to compare the objects,
437 * <code>null</code> means treat lhs as <code>Comparable</code>
438 * @return this - used to chain append calls
439 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
440 * with <code>lhs</code>
441 * @since 2.0
442 */
443 public CompareToBuilder append(Object lhs, Object rhs, Comparator comparator) {
444 if (comparison != 0) {
445 return this;
446 }
447 if (lhs == rhs) {
448 return this;
449 }
450 if (lhs == null) {
451 comparison = -1;
452 return this;
453 }
454 if (rhs == null) {
455 comparison = +1;
456 return this;
457 }
458 if (lhs.getClass().isArray()) {
459 // switch on type of array, to dispatch to the correct handler
460 // handles multi dimensional arrays
461 // throws a ClassCastException if rhs is not the correct array type
462 if (lhs instanceof long[]) {
463 append((long[]) lhs, (long[]) rhs);
464 } else if (lhs instanceof int[]) {
465 append((int[]) lhs, (int[]) rhs);
466 } else if (lhs instanceof short[]) {
467 append((short[]) lhs, (short[]) rhs);
468 } else if (lhs instanceof char[]) {
469 append((char[]) lhs, (char[]) rhs);
470 } else if (lhs instanceof byte[]) {
471 append((byte[]) lhs, (byte[]) rhs);
472 } else if (lhs instanceof double[]) {
473 append((double[]) lhs, (double[]) rhs);
474 } else if (lhs instanceof float[]) {
475 append((float[]) lhs, (float[]) rhs);
476 } else if (lhs instanceof boolean[]) {
477 append((boolean[]) lhs, (boolean[]) rhs);
478 } else {
479 // not an array of primitives
480 // throws a ClassCastException if rhs is not an array
481 append((Object[]) lhs, (Object[]) rhs, comparator);
482 }
483 } else {
484 // the simple case, not an array, just test the element
485 if (comparator == null) {
486 comparison = ((Comparable) lhs).compareTo(rhs);
487 } else {
488 comparison = comparator.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 = NumberUtils.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 = NumberUtils.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