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.HashSet;
024 import java.util.Set;
025
026 import org.apache.commons.lang3.ArrayUtils;
027 import org.apache.commons.lang3.Pair;
028
029 /**
030 * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
031 *
032 * <p> This class provides methods to build a good equals method for any
033 * class. It follows rules laid out in
034 * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
035 * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
036 * <code>floats</code>, and arrays can be tricky. Also, making sure that
037 * <code>equals()</code> and <code>hashCode()</code> are consistent can be
038 * difficult.</p>
039 *
040 * <p>Two Objects that compare as equals must generate the same hash code,
041 * but two Objects with the same hash code do not have to be equal.</p>
042 *
043 * <p>All relevant fields should be included in the calculation of equals.
044 * Derived fields may be ignored. In particular, any field used in
045 * generating a hash code must be used in the equals method, and vice
046 * versa.</p>
047 *
048 * <p>Typical use for the code is as follows:</p>
049 * <pre>
050 * public boolean equals(Object obj) {
051 * if (obj == null) { return false; }
052 * if (obj == this) { return true; }
053 * if (obj.getClass() != getClass()) {
054 * return false;
055 * }
056 * MyClass rhs = (MyClass) obj;
057 * return new EqualsBuilder()
058 * .appendSuper(super.equals(obj))
059 * .append(field1, rhs.field1)
060 * .append(field2, rhs.field2)
061 * .append(field3, rhs.field3)
062 * .isEquals();
063 * }
064 * </pre>
065 *
066 * <p> Alternatively, there is a method that uses reflection to determine
067 * the fields to test. Because these fields are usually private, the method,
068 * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
069 * change the visibility of the fields. This will fail under a security
070 * manager, unless the appropriate permissions are set up correctly. It is
071 * also slower than testing explicitly.</p>
072 *
073 * <p> A typical invocation for this method would look like:</p>
074 * <pre>
075 * public boolean equals(Object obj) {
076 * return EqualsBuilder.reflectionEquals(this, obj);
077 * }
078 * </pre>
079 *
080 * @author Apache Software Foundation
081 * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
082 * @author Gary Gregory
083 * @author Pete Gieser
084 * @author Arun Mammen Thomas
085 * @author Oliver Sauder
086 * @since 1.0
087 * @version $Id: EqualsBuilder.java 925674 2010-03-20 20:20:26Z bayard $
088 */
089 public class EqualsBuilder implements Builder<Boolean> {
090
091 /**
092 * <p>
093 * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
094 * </p>
095 *
096 * @since 3.0
097 */
098 private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<Set<Pair<IDKey, IDKey>>>();
099
100 /*
101 * N.B. we cannot store the actual objects in a HashSet, as that would use the very hashCode()
102 * we are in the process of calculating.
103 *
104 * So we generate a one-to-one mapping from the original object to a new object.
105 *
106 * Now HashSet uses equals() to determine if two elements with the same hashcode really
107 * are equal, so we also need to ensure that the replacement objects are only equal
108 * if the original objects are identical.
109 *
110 * The original implementation (2.4 and before) used the System.indentityHashCode()
111 * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
112 *
113 * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
114 * to disambiguate the duplicate ids.
115 */
116
117 /**
118 * <p>
119 * Returns the registry of object pairs being traversed by the reflection
120 * methods in the current thread.
121 * </p>
122 *
123 * @return Set the registry of objects being traversed
124 * @since 3.0
125 */
126 static Set<Pair<IDKey, IDKey>> getRegistry() {
127 return REGISTRY.get();
128 }
129
130 /**
131 * <p>
132 * Converters value pair into a register pair.
133 * </p>
134 *
135 * @param lhs <code>this</code> object
136 * @param rhs the other object
137 *
138 * @return
139 */
140 static Pair<IDKey, IDKey> getRegisterPair(Object lhs, Object rhs) {
141 IDKey left = new IDKey(lhs);
142 IDKey right = new IDKey(rhs);
143 return new Pair<IDKey, IDKey>(left, right);
144 }
145
146 /**
147 * <p>
148 * Returns <code>true</code> if the registry contains the given object pair.
149 * Used by the reflection methods to avoid infinite loops.
150 * Objects might be swapped therefore a check is needed if the object pair
151 * is registered in given or swapped order.
152 * </p>
153 *
154 * @param lhs <code>this</code> object to lookup in registry
155 * @param rhs the other object to lookup on registry
156 * @return boolean <code>true</code> if the registry contains the given object.
157 * @since 3.0
158 */
159 static boolean isRegistered(Object lhs, Object rhs) {
160 Set<Pair<IDKey, IDKey>> registry = getRegistry();
161 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
162 Pair<IDKey, IDKey> swappedPair = new Pair<IDKey, IDKey>(pair.right,
163 pair.left);
164
165 return registry != null
166 && (registry.contains(pair) || registry.contains(swappedPair));
167 }
168
169 /**
170 * <p>
171 * Registers the given object pair.
172 * Used by the reflection methods to avoid infinite loops.
173 * </p>
174 *
175 * @param lhs <code>this</code> object to register
176 * @param rhs the other object to register
177 */
178 static void register(Object lhs, Object rhs) {
179 synchronized (HashCodeBuilder.class) {
180 if (getRegistry() == null) {
181 REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>());
182 }
183 }
184
185 Set<Pair<IDKey, IDKey>> registry = getRegistry();
186 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
187 registry.add(pair);
188 }
189
190 /**
191 * <p>
192 * Unregisters the given object pair.
193 * </p>
194 *
195 * <p>
196 * Used by the reflection methods to avoid infinite loops.
197 *
198 * @param lhs <code>this</code> object to unregister
199 * @param rhs the other object to unregister
200 * @since 3.0
201 */
202 static void unregister(Object lhs, Object rhs) {
203 Set<Pair<IDKey, IDKey>> registry = getRegistry();
204 if (registry != null) {
205 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
206 registry.remove(pair);
207 synchronized (HashCodeBuilder.class) {
208 //read again
209 registry = getRegistry();
210 if (registry != null && registry.isEmpty()) {
211 REGISTRY.remove();
212 }
213 }
214 }
215 }
216
217 /**
218 * If the fields tested are equals.
219 * The default value is <code>true</code>.
220 */
221 private boolean isEquals = true;
222
223 /**
224 * <p>Constructor for EqualsBuilder.</p>
225 *
226 * <p>Starts off assuming that equals is <code>true</code>.</p>
227 * @see Object#equals(Object)
228 */
229 public EqualsBuilder() {
230 // do nothing for now.
231 }
232
233 //-------------------------------------------------------------------------
234
235 /**
236 * <p>This method uses reflection to determine if the two <code>Object</code>s
237 * are equal.</p>
238 *
239 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
240 * fields. This means that it will throw a security exception if run under
241 * a security manager, if the permissions are not set up correctly. It is also
242 * not as efficient as testing explicitly.</p>
243 *
244 * <p>Transient members will be not be tested, as they are likely derived
245 * fields, and not part of the value of the Object.</p>
246 *
247 * <p>Static fields will not be tested. Superclass fields will be included.</p>
248 *
249 * @param lhs <code>this</code> object
250 * @param rhs the other object
251 * @return <code>true</code> if the two Objects have tested equals.
252 */
253 public static boolean reflectionEquals(Object lhs, Object rhs) {
254 return reflectionEquals(lhs, rhs, false, null, null);
255 }
256
257 /**
258 * <p>This method uses reflection to determine if the two <code>Object</code>s
259 * are equal.</p>
260 *
261 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
262 * fields. This means that it will throw a security exception if run under
263 * a security manager, if the permissions are not set up correctly. It is also
264 * not as efficient as testing explicitly.</p>
265 *
266 * <p>Transient members will be not be tested, as they are likely derived
267 * fields, and not part of the value of the Object.</p>
268 *
269 * <p>Static fields will not be tested. Superclass fields will be included.</p>
270 *
271 * @param lhs <code>this</code> object
272 * @param rhs the other object
273 * @param excludeFields Collection of String field names to exclude from testing
274 * @return <code>true</code> if the two Objects have tested equals.
275 */
276 public static boolean reflectionEquals(Object lhs, Object rhs, Collection<String> excludeFields) {
277 return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
278 }
279
280 /**
281 * <p>This method uses reflection to determine if the two <code>Object</code>s
282 * are equal.</p>
283 *
284 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
285 * fields. This means that it will throw a security exception if run under
286 * a security manager, if the permissions are not set up correctly. It is also
287 * not as efficient as testing explicitly.</p>
288 *
289 * <p>Transient members will be not be tested, as they are likely derived
290 * fields, and not part of the value of the Object.</p>
291 *
292 * <p>Static fields will not be tested. Superclass fields will be included.</p>
293 *
294 * @param lhs <code>this</code> object
295 * @param rhs the other object
296 * @param excludeFields array of field names to exclude from testing
297 * @return <code>true</code> if the two Objects have tested equals.
298 */
299 public static boolean reflectionEquals(Object lhs, Object rhs, String[] excludeFields) {
300 return reflectionEquals(lhs, rhs, false, null, excludeFields);
301 }
302
303 /**
304 * <p>This method uses reflection to determine if the two <code>Object</code>s
305 * are equal.</p>
306 *
307 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
308 * fields. This means that it will throw a security exception if run under
309 * a security manager, if the permissions are not set up correctly. It is also
310 * not as efficient as testing explicitly.</p>
311 *
312 * <p>If the TestTransients parameter is set to <code>true</code>, transient
313 * members will be tested, otherwise they are ignored, as they are likely
314 * derived fields, and not part of the value of the <code>Object</code>.</p>
315 *
316 * <p>Static fields will not be tested. Superclass fields will be included.</p>
317 *
318 * @param lhs <code>this</code> object
319 * @param rhs the other object
320 * @param testTransients whether to include transient fields
321 * @return <code>true</code> if the two Objects have tested equals.
322 */
323 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
324 return reflectionEquals(lhs, rhs, testTransients, null, null);
325 }
326
327 /**
328 * <p>This method uses reflection to determine if the two <code>Object</code>s
329 * are equal.</p>
330 *
331 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
332 * fields. This means that it will throw a security exception if run under
333 * a security manager, if the permissions are not set up correctly. It is also
334 * not as efficient as testing explicitly.</p>
335 *
336 * <p>If the testTransients parameter is set to <code>true</code>, transient
337 * members will be tested, otherwise they are ignored, as they are likely
338 * derived fields, and not part of the value of the <code>Object</code>.</p>
339 *
340 * <p>Static fields will not be included. Superclass fields will be appended
341 * up to and including the specified superclass. A null superclass is treated
342 * as java.lang.Object.</p>
343 *
344 * @param lhs <code>this</code> object
345 * @param rhs the other object
346 * @param testTransients whether to include transient fields
347 * @param reflectUpToClass the superclass to reflect up to (inclusive),
348 * may be <code>null</code>
349 * @return <code>true</code> if the two Objects have tested equals.
350 * @since 2.0
351 */
352 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass) {
353 return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, null);
354 }
355
356 /**
357 * <p>This method uses reflection to determine if the two <code>Object</code>s
358 * are equal.</p>
359 *
360 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
361 * fields. This means that it will throw a security exception if run under
362 * a security manager, if the permissions are not set up correctly. It is also
363 * not as efficient as testing explicitly.</p>
364 *
365 * <p>If the testTransients parameter is set to <code>true</code>, transient
366 * members will be tested, otherwise they are ignored, as they are likely
367 * derived fields, and not part of the value of the <code>Object</code>.</p>
368 *
369 * <p>Static fields will not be included. Superclass fields will be appended
370 * up to and including the specified superclass. A null superclass is treated
371 * as java.lang.Object.</p>
372 *
373 * @param lhs <code>this</code> object
374 * @param rhs the other object
375 * @param testTransients whether to include transient fields
376 * @param reflectUpToClass the superclass to reflect up to (inclusive),
377 * may be <code>null</code>
378 * @param excludeFields array of field names to exclude from testing
379 * @return <code>true</code> if the two Objects have tested equals.
380 * @since 2.0
381 */
382 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass,
383 String[] excludeFields) {
384 if (lhs == rhs) {
385 return true;
386 }
387 if (lhs == null || rhs == null) {
388 return false;
389 }
390 // Find the leaf class since there may be transients in the leaf
391 // class or in classes between the leaf and root.
392 // If we are not testing transients or a subclass has no ivars,
393 // then a subclass can test equals to a superclass.
394 Class<?> lhsClass = lhs.getClass();
395 Class<?> rhsClass = rhs.getClass();
396 Class<?> testClass;
397 if (lhsClass.isInstance(rhs)) {
398 testClass = lhsClass;
399 if (!rhsClass.isInstance(lhs)) {
400 // rhsClass is a subclass of lhsClass
401 testClass = rhsClass;
402 }
403 } else if (rhsClass.isInstance(lhs)) {
404 testClass = rhsClass;
405 if (!lhsClass.isInstance(rhs)) {
406 // lhsClass is a subclass of rhsClass
407 testClass = lhsClass;
408 }
409 } else {
410 // The two classes are not related.
411 return false;
412 }
413 EqualsBuilder equalsBuilder = new EqualsBuilder();
414 try {
415 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
416 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
417 testClass = testClass.getSuperclass();
418 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
419 }
420 } catch (IllegalArgumentException e) {
421 // In this case, we tried to test a subclass vs. a superclass and
422 // the subclass has ivars or the ivars are transient and
423 // we are testing transients.
424 // If a subclass has ivars that we are trying to test them, we get an
425 // exception and we know that the objects are not equal.
426 return false;
427 }
428 return equalsBuilder.isEquals();
429 }
430
431 /**
432 * <p>Appends the fields and values defined by the given object of the
433 * given Class.</p>
434 *
435 * @param lhs the left hand object
436 * @param rhs the right hand object
437 * @param clazz the class to append details of
438 * @param builder the builder to append to
439 * @param useTransients whether to test transient fields
440 * @param excludeFields array of field names to exclude from testing
441 */
442 private static void reflectionAppend(
443 Object lhs,
444 Object rhs,
445 Class<?> clazz,
446 EqualsBuilder builder,
447 boolean useTransients,
448 String[] excludeFields) {
449
450 if (isRegistered(lhs, rhs)) {
451 return;
452 }
453
454 try {
455 register(lhs, rhs);
456 Field[] fields = clazz.getDeclaredFields();
457 AccessibleObject.setAccessible(fields, true);
458 for (int i = 0; i < fields.length && builder.isEquals; i++) {
459 Field f = fields[i];
460 if (!ArrayUtils.contains(excludeFields, f.getName())
461 && (f.getName().indexOf('$') == -1)
462 && (useTransients || !Modifier.isTransient(f.getModifiers()))
463 && (!Modifier.isStatic(f.getModifiers()))) {
464 try {
465 builder.append(f.get(lhs), f.get(rhs));
466 } catch (IllegalAccessException e) {
467 //this can't happen. Would get a Security exception instead
468 //throw a runtime exception in case the impossible happens.
469 throw new InternalError("Unexpected IllegalAccessException");
470 }
471 }
472 }
473 } finally {
474 unregister(lhs, rhs);
475 }
476 }
477
478 //-------------------------------------------------------------------------
479
480 /**
481 * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
482 *
483 * @param superEquals the result of calling <code>super.equals()</code>
484 * @return EqualsBuilder - used to chain calls.
485 * @since 2.0
486 */
487 public EqualsBuilder appendSuper(boolean superEquals) {
488 if (isEquals == false) {
489 return this;
490 }
491 isEquals = superEquals;
492 return this;
493 }
494
495 //-------------------------------------------------------------------------
496
497 /**
498 * <p>Test if two <code>Object</code>s are equal using their
499 * <code>equals</code> method.</p>
500 *
501 * @param lhs the left hand object
502 * @param rhs the right hand object
503 * @return EqualsBuilder - used to chain calls.
504 */
505 public EqualsBuilder append(Object lhs, Object rhs) {
506 if (isEquals == false) {
507 return this;
508 }
509 if (lhs == rhs) {
510 return this;
511 }
512 if (lhs == null || rhs == null) {
513 this.setEquals(false);
514 return this;
515 }
516 Class<?> lhsClass = lhs.getClass();
517 if (!lhsClass.isArray()) {
518 // The simple case, not an array, just test the element
519 isEquals = lhs.equals(rhs);
520 } else if (lhs.getClass() != rhs.getClass()) {
521 // Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
522 this.setEquals(false);
523 }
524 // 'Switch' on type of array, to dispatch to the correct handler
525 // This handles multi dimensional arrays of the same depth
526 else if (lhs instanceof long[]) {
527 append((long[]) lhs, (long[]) rhs);
528 } else if (lhs instanceof int[]) {
529 append((int[]) lhs, (int[]) rhs);
530 } else if (lhs instanceof short[]) {
531 append((short[]) lhs, (short[]) rhs);
532 } else if (lhs instanceof char[]) {
533 append((char[]) lhs, (char[]) rhs);
534 } else if (lhs instanceof byte[]) {
535 append((byte[]) lhs, (byte[]) rhs);
536 } else if (lhs instanceof double[]) {
537 append((double[]) lhs, (double[]) rhs);
538 } else if (lhs instanceof float[]) {
539 append((float[]) lhs, (float[]) rhs);
540 } else if (lhs instanceof boolean[]) {
541 append((boolean[]) lhs, (boolean[]) rhs);
542 } else {
543 // Not an array of primitives
544 append((Object[]) lhs, (Object[]) rhs);
545 }
546 return this;
547 }
548
549 /**
550 * <p>
551 * Test if two <code>long</code> s are equal.
552 * </p>
553 *
554 * @param lhs
555 * the left hand <code>long</code>
556 * @param rhs
557 * the right hand <code>long</code>
558 * @return EqualsBuilder - used to chain calls.
559 */
560 public EqualsBuilder append(long lhs, long rhs) {
561 if (isEquals == false) {
562 return this;
563 }
564 isEquals = (lhs == rhs);
565 return this;
566 }
567
568 /**
569 * <p>Test if two <code>int</code>s are equal.</p>
570 *
571 * @param lhs the left hand <code>int</code>
572 * @param rhs the right hand <code>int</code>
573 * @return EqualsBuilder - used to chain calls.
574 */
575 public EqualsBuilder append(int lhs, int rhs) {
576 if (isEquals == false) {
577 return this;
578 }
579 isEquals = (lhs == rhs);
580 return this;
581 }
582
583 /**
584 * <p>Test if two <code>short</code>s are equal.</p>
585 *
586 * @param lhs the left hand <code>short</code>
587 * @param rhs the right hand <code>short</code>
588 * @return EqualsBuilder - used to chain calls.
589 */
590 public EqualsBuilder append(short lhs, short rhs) {
591 if (isEquals == false) {
592 return this;
593 }
594 isEquals = (lhs == rhs);
595 return this;
596 }
597
598 /**
599 * <p>Test if two <code>char</code>s are equal.</p>
600 *
601 * @param lhs the left hand <code>char</code>
602 * @param rhs the right hand <code>char</code>
603 * @return EqualsBuilder - used to chain calls.
604 */
605 public EqualsBuilder append(char lhs, char rhs) {
606 if (isEquals == false) {
607 return this;
608 }
609 isEquals = (lhs == rhs);
610 return this;
611 }
612
613 /**
614 * <p>Test if two <code>byte</code>s are equal.</p>
615 *
616 * @param lhs the left hand <code>byte</code>
617 * @param rhs the right hand <code>byte</code>
618 * @return EqualsBuilder - used to chain calls.
619 */
620 public EqualsBuilder append(byte lhs, byte rhs) {
621 if (isEquals == false) {
622 return this;
623 }
624 isEquals = (lhs == rhs);
625 return this;
626 }
627
628 /**
629 * <p>Test if two <code>double</code>s are equal by testing that the
630 * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
631 *
632 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
633 *
634 * <p>It is compatible with the hash code generated by
635 * <code>HashCodeBuilder</code>.</p>
636 *
637 * @param lhs the left hand <code>double</code>
638 * @param rhs the right hand <code>double</code>
639 * @return EqualsBuilder - used to chain calls.
640 */
641 public EqualsBuilder append(double lhs, double rhs) {
642 if (isEquals == false) {
643 return this;
644 }
645 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
646 }
647
648 /**
649 * <p>Test if two <code>float</code>s are equal byt testing that the
650 * pattern of bits returned by doubleToLong are equal.</p>
651 *
652 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
653 *
654 * <p>It is compatible with the hash code generated by
655 * <code>HashCodeBuilder</code>.</p>
656 *
657 * @param lhs the left hand <code>float</code>
658 * @param rhs the right hand <code>float</code>
659 * @return EqualsBuilder - used to chain calls.
660 */
661 public EqualsBuilder append(float lhs, float rhs) {
662 if (isEquals == false) {
663 return this;
664 }
665 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
666 }
667
668 /**
669 * <p>Test if two <code>booleans</code>s are equal.</p>
670 *
671 * @param lhs the left hand <code>boolean</code>
672 * @param rhs the right hand <code>boolean</code>
673 * @return EqualsBuilder - used to chain calls.
674 */
675 public EqualsBuilder append(boolean lhs, boolean rhs) {
676 if (isEquals == false) {
677 return this;
678 }
679 isEquals = (lhs == rhs);
680 return this;
681 }
682
683 /**
684 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
685 *
686 * <p>This also will be called for the top level of
687 * multi-dimensional, ragged, and multi-typed arrays.</p>
688 *
689 * @param lhs the left hand <code>Object[]</code>
690 * @param rhs the right hand <code>Object[]</code>
691 * @return EqualsBuilder - used to chain calls.
692 */
693 public EqualsBuilder append(Object[] lhs, Object[] rhs) {
694 if (isEquals == false) {
695 return this;
696 }
697 if (lhs == rhs) {
698 return this;
699 }
700 if (lhs == null || rhs == null) {
701 this.setEquals(false);
702 return this;
703 }
704 if (lhs.length != rhs.length) {
705 this.setEquals(false);
706 return this;
707 }
708 for (int i = 0; i < lhs.length && isEquals; ++i) {
709 append(lhs[i], rhs[i]);
710 }
711 return this;
712 }
713
714 /**
715 * <p>Deep comparison of array of <code>long</code>. Length and all
716 * values are compared.</p>
717 *
718 * <p>The method {@link #append(long, long)} is used.</p>
719 *
720 * @param lhs the left hand <code>long[]</code>
721 * @param rhs the right hand <code>long[]</code>
722 * @return EqualsBuilder - used to chain calls.
723 */
724 public EqualsBuilder append(long[] lhs, long[] rhs) {
725 if (isEquals == false) {
726 return this;
727 }
728 if (lhs == rhs) {
729 return this;
730 }
731 if (lhs == null || rhs == null) {
732 this.setEquals(false);
733 return this;
734 }
735 if (lhs.length != rhs.length) {
736 this.setEquals(false);
737 return this;
738 }
739 for (int i = 0; i < lhs.length && isEquals; ++i) {
740 append(lhs[i], rhs[i]);
741 }
742 return this;
743 }
744
745 /**
746 * <p>Deep comparison of array of <code>int</code>. Length and all
747 * values are compared.</p>
748 *
749 * <p>The method {@link #append(int, int)} is used.</p>
750 *
751 * @param lhs the left hand <code>int[]</code>
752 * @param rhs the right hand <code>int[]</code>
753 * @return EqualsBuilder - used to chain calls.
754 */
755 public EqualsBuilder append(int[] lhs, int[] rhs) {
756 if (isEquals == false) {
757 return this;
758 }
759 if (lhs == rhs) {
760 return this;
761 }
762 if (lhs == null || rhs == null) {
763 this.setEquals(false);
764 return this;
765 }
766 if (lhs.length != rhs.length) {
767 this.setEquals(false);
768 return this;
769 }
770 for (int i = 0; i < lhs.length && isEquals; ++i) {
771 append(lhs[i], rhs[i]);
772 }
773 return this;
774 }
775
776 /**
777 * <p>Deep comparison of array of <code>short</code>. Length and all
778 * values are compared.</p>
779 *
780 * <p>The method {@link #append(short, short)} is used.</p>
781 *
782 * @param lhs the left hand <code>short[]</code>
783 * @param rhs the right hand <code>short[]</code>
784 * @return EqualsBuilder - used to chain calls.
785 */
786 public EqualsBuilder append(short[] lhs, short[] rhs) {
787 if (isEquals == false) {
788 return this;
789 }
790 if (lhs == rhs) {
791 return this;
792 }
793 if (lhs == null || rhs == null) {
794 this.setEquals(false);
795 return this;
796 }
797 if (lhs.length != rhs.length) {
798 this.setEquals(false);
799 return this;
800 }
801 for (int i = 0; i < lhs.length && isEquals; ++i) {
802 append(lhs[i], rhs[i]);
803 }
804 return this;
805 }
806
807 /**
808 * <p>Deep comparison of array of <code>char</code>. Length and all
809 * values are compared.</p>
810 *
811 * <p>The method {@link #append(char, char)} is used.</p>
812 *
813 * @param lhs the left hand <code>char[]</code>
814 * @param rhs the right hand <code>char[]</code>
815 * @return EqualsBuilder - used to chain calls.
816 */
817 public EqualsBuilder append(char[] lhs, char[] rhs) {
818 if (isEquals == false) {
819 return this;
820 }
821 if (lhs == rhs) {
822 return this;
823 }
824 if (lhs == null || rhs == null) {
825 this.setEquals(false);
826 return this;
827 }
828 if (lhs.length != rhs.length) {
829 this.setEquals(false);
830 return this;
831 }
832 for (int i = 0; i < lhs.length && isEquals; ++i) {
833 append(lhs[i], rhs[i]);
834 }
835 return this;
836 }
837
838 /**
839 * <p>Deep comparison of array of <code>byte</code>. Length and all
840 * values are compared.</p>
841 *
842 * <p>The method {@link #append(byte, byte)} is used.</p>
843 *
844 * @param lhs the left hand <code>byte[]</code>
845 * @param rhs the right hand <code>byte[]</code>
846 * @return EqualsBuilder - used to chain calls.
847 */
848 public EqualsBuilder append(byte[] lhs, byte[] rhs) {
849 if (isEquals == false) {
850 return this;
851 }
852 if (lhs == rhs) {
853 return this;
854 }
855 if (lhs == null || rhs == null) {
856 this.setEquals(false);
857 return this;
858 }
859 if (lhs.length != rhs.length) {
860 this.setEquals(false);
861 return this;
862 }
863 for (int i = 0; i < lhs.length && isEquals; ++i) {
864 append(lhs[i], rhs[i]);
865 }
866 return this;
867 }
868
869 /**
870 * <p>Deep comparison of array of <code>double</code>. Length and all
871 * values are compared.</p>
872 *
873 * <p>The method {@link #append(double, double)} is used.</p>
874 *
875 * @param lhs the left hand <code>double[]</code>
876 * @param rhs the right hand <code>double[]</code>
877 * @return EqualsBuilder - used to chain calls.
878 */
879 public EqualsBuilder append(double[] lhs, double[] rhs) {
880 if (isEquals == false) {
881 return this;
882 }
883 if (lhs == rhs) {
884 return this;
885 }
886 if (lhs == null || rhs == null) {
887 this.setEquals(false);
888 return this;
889 }
890 if (lhs.length != rhs.length) {
891 this.setEquals(false);
892 return this;
893 }
894 for (int i = 0; i < lhs.length && isEquals; ++i) {
895 append(lhs[i], rhs[i]);
896 }
897 return this;
898 }
899
900 /**
901 * <p>Deep comparison of array of <code>float</code>. Length and all
902 * values are compared.</p>
903 *
904 * <p>The method {@link #append(float, float)} is used.</p>
905 *
906 * @param lhs the left hand <code>float[]</code>
907 * @param rhs the right hand <code>float[]</code>
908 * @return EqualsBuilder - used to chain calls.
909 */
910 public EqualsBuilder append(float[] lhs, float[] rhs) {
911 if (isEquals == false) {
912 return this;
913 }
914 if (lhs == rhs) {
915 return this;
916 }
917 if (lhs == null || rhs == null) {
918 this.setEquals(false);
919 return this;
920 }
921 if (lhs.length != rhs.length) {
922 this.setEquals(false);
923 return this;
924 }
925 for (int i = 0; i < lhs.length && isEquals; ++i) {
926 append(lhs[i], rhs[i]);
927 }
928 return this;
929 }
930
931 /**
932 * <p>Deep comparison of array of <code>boolean</code>. Length and all
933 * values are compared.</p>
934 *
935 * <p>The method {@link #append(boolean, boolean)} is used.</p>
936 *
937 * @param lhs the left hand <code>boolean[]</code>
938 * @param rhs the right hand <code>boolean[]</code>
939 * @return EqualsBuilder - used to chain calls.
940 */
941 public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
942 if (isEquals == false) {
943 return this;
944 }
945 if (lhs == rhs) {
946 return this;
947 }
948 if (lhs == null || rhs == null) {
949 this.setEquals(false);
950 return this;
951 }
952 if (lhs.length != rhs.length) {
953 this.setEquals(false);
954 return this;
955 }
956 for (int i = 0; i < lhs.length && isEquals; ++i) {
957 append(lhs[i], rhs[i]);
958 }
959 return this;
960 }
961
962 /**
963 * <p>Returns <code>true</code> if the fields that have been checked
964 * are all equal.</p>
965 *
966 * @return boolean
967 */
968 public boolean isEquals() {
969 return this.isEquals;
970 }
971
972 /**
973 * <p>Returns <code>true</code> if the fields that have been checked
974 * are all equal.</p>
975 *
976 * @return <code>true</code> if all of the fields that have been checked
977 * are equal, <code>false</code> otherwise.
978 *
979 * @since 3.0
980 */
981 public Boolean build() {
982 return isEquals();
983 }
984
985 /**
986 * Sets the <code>isEquals</code> value.
987 *
988 * @param isEquals The value to set.
989 * @since 2.1
990 */
991 protected void setEquals(boolean isEquals) {
992 this.isEquals = isEquals;
993 }
994
995 /**
996 * Reset the EqualsBuilder so you can use the same object again
997 * @since 2.5
998 */
999 public void reset() {
1000 this.isEquals = true;
1001 }
1002 }