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