1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 package net.sf.classifier4J.util;
55
56 import java.lang.reflect.AccessibleObject;
57 import java.lang.reflect.Field;
58 import java.lang.reflect.Modifier;
59
60 /***
61 * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
62 *
63 * <p>Originally from the Apache commons-lang package</p>
64 *
65 * <p> This class provides methods to build a good equals method for any
66 * class. It follows rules laid out in
67 * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
68 * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
69 * <code>floats</code>, and arrays can be tricky. Also, making sure that
70 * <code>equals()</code> and <code>hashCode()</code> are consistent can be
71 * difficult.</p>
72 *
73 * <p>Two Objects that compare as equals must generate the same hash code,
74 * but two Objects with the same hash code do not have to be equal.</p>
75 *
76 * <p>All relevant fields should be included in the calculation of equals.
77 * Derived fields may be ignored. In particular, any field used in
78 * generating a hash code must be used in the equals method, and vice
79 * versa.</p>
80 *
81 * <p>Typical use for the code is as follows:</p>
82 * <pre>
83 * public boolean equals(Object o) {
84 * if ( !(o instanceof MyClass) ) {
85 * return false;
86 * }
87 * MyClass rhs = (MyClass) o;
88 * return new EqualsBuilder()
89 * .appendSuper(super.equals(o))
90 * .append(field1, rhs.field1)
91 * .append(field2, rhs.field2)
92 * .append(field3, rhs.field3)
93 * .isEquals();
94 * }
95 * </pre>
96 *
97 * <p> Alternatively, there is a method that uses reflection to determine
98 * the fields to test. Because these fields are usually private, the method,
99 * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
100 * change the visibility of the fields. This will fail under a security
101 * manager, unless the appropriate permissions are set up correctly. It is
102 * also slower than testing explicitly.</p>
103 *
104 * <p> A typical invocation for this method would look like:</p>
105 * <pre>
106 * public boolean equals(Object o) {
107 * return EqualsBuilder.reflectionEquals(this, o);
108 * }
109 * </pre>
110 *
111 * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
112 * @author Stephen Colebourne
113 * @author Gary Gregory
114 * @author Pete Gieser
115 * @since 1.0
116 * @version $Id: EqualsBuilder.java,v 1.1 2005/02/04 05:30:28 nicklothian Exp $
117 */
118 public class EqualsBuilder {
119 /***
120 * If the fields tested are equals.
121 */
122 private boolean isEquals;
123
124 /***
125 * <p>Constructor for EqualsBuilder.</p>
126 *
127 * <p>Starts off assuming that equals is <code>true</code>.</p>
128 * @see java.lang.Object#equals
129 */
130 public EqualsBuilder() {
131 super();
132 isEquals = true;
133 }
134
135
136
137 /***
138 * <p>This method uses reflection to determine if the two <code>Object</code>s
139 * are equal.</p>
140 *
141 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
142 * fields. This means that it will throw a security exception if run under
143 * a security manager, if the permissions are not set up correctly. It is also
144 * not as efficient as testing explicitly.</p>
145 *
146 * <p>Transient members will be not be tested, as they are likely derived
147 * fields, and not part of the value of the Object.</p>
148 *
149 * <p>Static fields will not be tested. Superclass fields will be included.</p>
150 *
151 * @param lhs <code>this</code> object
152 * @param rhs the other object
153 * @return <code>true</code> if the two Objects have tested equals.
154 */
155 public static boolean reflectionEquals(Object lhs, Object rhs) {
156 return reflectionEquals(lhs, rhs, false, null);
157 }
158
159 /***
160 * <p>This method uses reflection to determine if the two <code>Object</code>s
161 * are equal.</p>
162 *
163 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
164 * fields. This means that it will throw a security exception if run under
165 * a security manager, if the permissions are not set up correctly. It is also
166 * not as efficient as testing explicitly.</p>
167 *
168 * <p>If the TestTransients parameter is set to <code>true</code>, transient
169 * members will be tested, otherwise they are ignored, as they are likely
170 * derived fields, and not part of the value of the <code>Object</code>.</p>
171 *
172 * <p>Static fields will not be tested. Superclass fields will be included.</p>
173 *
174 * @param lhs <code>this</code> object
175 * @param rhs the other object
176 * @param testTransients whether to include transient fields
177 * @return <code>true</code> if the two Objects have tested equals.
178 */
179 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
180 return reflectionEquals(lhs, rhs, testTransients, null);
181 }
182
183 /***
184 * <p>This method uses reflection to determine if the two <code>Object</code>s
185 * are equal.</p>
186 *
187 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
188 * fields. This means that it will throw a security exception if run under
189 * a security manager, if the permissions are not set up correctly. It is also
190 * not as efficient as testing explicitly.</p>
191 *
192 * <p>If the testTransients parameter is set to <code>true</code>, transient
193 * members will be tested, otherwise they are ignored, as they are likely
194 * derived fields, and not part of the value of the <code>Object</code>.</p>
195 *
196 * <p>Static fields will not be included. Superclass fields will be appended
197 * up to and including the specified superclass. A null superclass is treated
198 * as java.lang.Object.</p>
199 *
200 * @param lhs <code>this</code> object
201 * @param rhs the other object
202 * @param testTransients whether to include transient fields
203 * @param reflectUpToClass the superclass to reflect up to (inclusive),
204 * may be <code>null</code>
205 * @return <code>true</code> if the two Objects have tested equals.
206 * @since 2.0
207 */
208 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass) {
209 if (lhs == rhs) {
210 return true;
211 }
212 if (lhs == null || rhs == null) {
213 return false;
214 }
215
216
217
218
219 Class lhsClass = lhs.getClass();
220 Class rhsClass = rhs.getClass();
221 Class testClass;
222 if (lhsClass.isInstance(rhs)) {
223 testClass = lhsClass;
224 if (!rhsClass.isInstance(lhs)) {
225
226 testClass = rhsClass;
227 }
228 } else if (rhsClass.isInstance(lhs)) {
229 testClass = rhsClass;
230 if (!lhsClass.isInstance(rhs)) {
231
232 testClass = lhsClass;
233 }
234 } else {
235
236 return false;
237 }
238 EqualsBuilder equalsBuilder = new EqualsBuilder();
239 try {
240 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
241 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
242 testClass = testClass.getSuperclass();
243 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
244 }
245 } catch (IllegalArgumentException e) {
246
247
248
249
250
251 return false;
252 }
253 return equalsBuilder.isEquals();
254 }
255
256 /***
257 * <p>Appends the fields and values defined by the given object of the
258 * given Class.</p>
259 *
260 * @param lhs the left hand object
261 * @param rhs the right hand object
262 * @param clazz the class to append details of
263 * @param builder the builder to append to
264 * @param useTransients whether to test transient fields
265 */
266 private static void reflectionAppend(
267 Object lhs,
268 Object rhs,
269 Class clazz,
270 EqualsBuilder builder,
271 boolean useTransients) {
272 Field[] fields = clazz.getDeclaredFields();
273 AccessibleObject.setAccessible(fields, true);
274 for (int i = 0; i < fields.length && builder.isEquals; i++) {
275 Field f = fields[i];
276 if ((f.getName().indexOf('$') == -1)
277 && (useTransients || !Modifier.isTransient(f.getModifiers()))
278 && (!Modifier.isStatic(f.getModifiers()))) {
279 try {
280 builder.append(f.get(lhs), f.get(rhs));
281 } catch (IllegalAccessException e) {
282
283
284 throw new InternalError("Unexpected IllegalAccessException");
285 }
286 }
287 }
288 }
289
290
291
292 /***
293 * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
294 *
295 * @param superEquals the result of calling <code>super.equals()</code>
296 * @return EqualsBuilder - used to chain calls.
297 * @since 2.0
298 */
299 public EqualsBuilder appendSuper(boolean superEquals) {
300 if (isEquals == false) {
301 return this;
302 }
303 isEquals = superEquals;
304 return this;
305 }
306
307
308
309 /***
310 * <p>Test if two <code>Object</code>s are equal using their
311 * <code>equals</code> method.</p>
312 *
313 * @param lhs the left hand object
314 * @param rhs the right hand object
315 * @return EqualsBuilder - used to chain calls.
316 */
317 public EqualsBuilder append(Object lhs, Object rhs) {
318 if (isEquals == false) {
319 return this;
320 }
321 if (lhs == rhs) {
322 return this;
323 }
324 if (lhs == null || rhs == null) {
325 isEquals = false;
326 return this;
327 }
328 Class lhsClass = lhs.getClass();
329 if (!lhsClass.isArray()) {
330
331 isEquals = lhs.equals(rhs);
332 } else {
333
334
335 if (lhs instanceof long[]) {
336 append((long[]) lhs, (long[]) rhs);
337 } else if (lhs instanceof int[]) {
338 append((int[]) lhs, (int[]) rhs);
339 } else if (lhs instanceof short[]) {
340 append((short[]) lhs, (short[]) rhs);
341 } else if (lhs instanceof char[]) {
342 append((char[]) lhs, (char[]) rhs);
343 } else if (lhs instanceof byte[]) {
344 append((byte[]) lhs, (byte[]) rhs);
345 } else if (lhs instanceof double[]) {
346 append((double[]) lhs, (double[]) rhs);
347 } else if (lhs instanceof float[]) {
348 append((float[]) lhs, (float[]) rhs);
349 } else if (lhs instanceof boolean[]) {
350 append((boolean[]) lhs, (boolean[]) rhs);
351 } else {
352
353 append((Object[]) lhs, (Object[]) rhs);
354 }
355 }
356 return this;
357 }
358
359 /***
360 * <p>Test if two <code>long</code>s are equal.</p>
361 *
362 * @param lhs the left hand <code>long</code>
363 * @param rhs the right hand <code>long</code>
364 * @return EqualsBuilder - used to chain calls.
365 */
366 public EqualsBuilder append(long lhs, long rhs) {
367 if (isEquals == false) {
368 return this;
369 }
370 isEquals = (lhs == rhs);
371 return this;
372 }
373
374 /***
375 * <p>Test if two <code>int</code>s are equal.</p>
376 *
377 * @param lhs the left hand <code>int</code>
378 * @param rhs the right hand <code>int</code>
379 * @return EqualsBuilder - used to chain calls.
380 */
381 public EqualsBuilder append(int lhs, int rhs) {
382 if (isEquals == false) {
383 return this;
384 }
385 isEquals = (lhs == rhs);
386 return this;
387 }
388
389 /***
390 * <p>Test if two <code>short</code>s are equal.</p>
391 *
392 * @param lhs the left hand <code>short</code>
393 * @param rhs the right hand <code>short</code>
394 * @return EqualsBuilder - used to chain calls.
395 */
396 public EqualsBuilder append(short lhs, short rhs) {
397 if (isEquals == false) {
398 return this;
399 }
400 isEquals = (lhs == rhs);
401 return this;
402 }
403
404 /***
405 * <p>Test if two <code>char</code>s are equal.</p>
406 *
407 * @param lhs the left hand <code>char</code>
408 * @param rhs the right hand <code>char</code>
409 * @return EqualsBuilder - used to chain calls.
410 */
411 public EqualsBuilder append(char lhs, char rhs) {
412 if (isEquals == false) {
413 return this;
414 }
415 isEquals = (lhs == rhs);
416 return this;
417 }
418
419 /***
420 * <p>Test if two <code>byte</code>s are equal.</p>
421 *
422 * @param lhs the left hand <code>byte</code>
423 * @param rhs the right hand <code>byte</code>
424 * @return EqualsBuilder - used to chain calls.
425 */
426 public EqualsBuilder append(byte lhs, byte rhs) {
427 if (isEquals == false) {
428 return this;
429 }
430 isEquals = (lhs == rhs);
431 return this;
432 }
433
434 /***
435 * <p>Test if two <code>double</code>s are equal by testing that the
436 * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
437 *
438 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
439 *
440 * <p>It is compatible with the hash code generated by
441 * <code>HashCodeBuilder</code>.</p>
442 *
443 * @param lhs the left hand <code>double</code>
444 * @param rhs the right hand <code>double</code>
445 * @return EqualsBuilder - used to chain calls.
446 */
447 public EqualsBuilder append(double lhs, double rhs) {
448 if (isEquals == false) {
449 return this;
450 }
451 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
452 }
453
454 /***
455 * <p>Test if two <code>float</code>s are equal byt testing that the
456 * pattern of bits returned by doubleToLong are equal.</p>
457 *
458 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
459 *
460 * <p>It is compatible with the hash code generated by
461 * <code>HashCodeBuilder</code>.</p>
462 *
463 * @param lhs the left hand <code>float</code>
464 * @param rhs the right hand <code>float</code>
465 * @return EqualsBuilder - used to chain calls.
466 */
467 public EqualsBuilder append(float lhs, float rhs) {
468 if (isEquals == false) {
469 return this;
470 }
471 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
472 }
473
474 /***
475 * <p>Test if two <code>booleans</code>s are equal.</p>
476 *
477 * @param lhs the left hand <code>boolean</code>
478 * @param rhs the right hand <code>boolean</code>
479 * @return EqualsBuilder - used to chain calls.
480 */
481 public EqualsBuilder append(boolean lhs, boolean rhs) {
482 if (isEquals == false) {
483 return this;
484 }
485 isEquals = (lhs == rhs);
486 return this;
487 }
488
489 /***
490 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
491 *
492 * <p>This also will be called for the top level of
493 * multi-dimensional, ragged, and multi-typed arrays.</p>
494 *
495 * @param lhs the left hand <code>Object[]</code>
496 * @param rhs the right hand <code>Object[]</code>
497 * @return EqualsBuilder - used to chain calls.
498 */
499 public EqualsBuilder append(Object[] lhs, Object[] rhs) {
500 if (isEquals == false) {
501 return this;
502 }
503 if (lhs == rhs) {
504 return this;
505 }
506 if (lhs == null || rhs == null) {
507 isEquals = false;
508 return this;
509 }
510 if (lhs.length != rhs.length) {
511 isEquals = false;
512 return this;
513 }
514 for (int i = 0; i < lhs.length && isEquals; ++i) {
515 Class lhsClass = lhs[i].getClass();
516 if (!lhsClass.isInstance(rhs[i])) {
517 isEquals = false;
518 break;
519 }
520 append(lhs[i], rhs[i]);
521 }
522 return this;
523 }
524
525 /***
526 * <p>Deep comparison of array of <code>long</code>. Length and all
527 * values are compared.</p>
528 *
529 * <p>The method {@link #append(long, long)} is used.</p>
530 *
531 * @param lhs the left hand <code>long[]</code>
532 * @param rhs the right hand <code>long[]</code>
533 * @return EqualsBuilder - used to chain calls.
534 */
535 public EqualsBuilder append(long[] lhs, long[] rhs) {
536 if (isEquals == false) {
537 return this;
538 }
539 if (lhs == rhs) {
540 return this;
541 }
542 if (lhs == null || rhs == null) {
543 isEquals = false;
544 return this;
545 }
546 if (lhs.length != rhs.length) {
547 isEquals = false;
548 return this;
549 }
550 for (int i = 0; i < lhs.length && isEquals; ++i) {
551 append(lhs[i], rhs[i]);
552 }
553 return this;
554 }
555
556 /***
557 * <p>Deep comparison of array of <code>int</code>. Length and all
558 * values are compared.</p>
559 *
560 * <p>The method {@link #append(int, int)} is used.</p>
561 *
562 * @param lhs the left hand <code>int[]</code>
563 * @param rhs the right hand <code>int[]</code>
564 * @return EqualsBuilder - used to chain calls.
565 */
566 public EqualsBuilder append(int[] lhs, int[] rhs) {
567 if (isEquals == false) {
568 return this;
569 }
570 if (lhs == rhs) {
571 return this;
572 }
573 if (lhs == null || rhs == null) {
574 isEquals = false;
575 return this;
576 }
577 if (lhs.length != rhs.length) {
578 isEquals = false;
579 return this;
580 }
581 for (int i = 0; i < lhs.length && isEquals; ++i) {
582 append(lhs[i], rhs[i]);
583 }
584 return this;
585 }
586
587 /***
588 * <p>Deep comparison of array of <code>short</code>. Length and all
589 * values are compared.</p>
590 *
591 * <p>The method {@link #append(short, short)} is used.</p>
592 *
593 * @param lhs the left hand <code>short[]</code>
594 * @param rhs the right hand <code>short[]</code>
595 * @return EqualsBuilder - used to chain calls.
596 */
597 public EqualsBuilder append(short[] lhs, short[] rhs) {
598 if (isEquals == false) {
599 return this;
600 }
601 if (lhs == rhs) {
602 return this;
603 }
604 if (lhs == null || rhs == null) {
605 isEquals = false;
606 return this;
607 }
608 if (lhs.length != rhs.length) {
609 isEquals = false;
610 return this;
611 }
612 for (int i = 0; i < lhs.length && isEquals; ++i) {
613 append(lhs[i], rhs[i]);
614 }
615 return this;
616 }
617
618 /***
619 * <p>Deep comparison of array of <code>char</code>. Length and all
620 * values are compared.</p>
621 *
622 * <p>The method {@link #append(char, char)} is used.</p>
623 *
624 * @param lhs the left hand <code>char[]</code>
625 * @param rhs the right hand <code>char[]</code>
626 * @return EqualsBuilder - used to chain calls.
627 */
628 public EqualsBuilder append(char[] lhs, char[] rhs) {
629 if (isEquals == false) {
630 return this;
631 }
632 if (lhs == rhs) {
633 return this;
634 }
635 if (lhs == null || rhs == null) {
636 isEquals = false;
637 return this;
638 }
639 if (lhs.length != rhs.length) {
640 isEquals = false;
641 return this;
642 }
643 for (int i = 0; i < lhs.length && isEquals; ++i) {
644 append(lhs[i], rhs[i]);
645 }
646 return this;
647 }
648
649 /***
650 * <p>Deep comparison of array of <code>byte</code>. Length and all
651 * values are compared.</p>
652 *
653 * <p>The method {@link #append(byte, byte)} is used.</p>
654 *
655 * @param lhs the left hand <code>byte[]</code>
656 * @param rhs the right hand <code>byte[]</code>
657 * @return EqualsBuilder - used to chain calls.
658 */
659 public EqualsBuilder append(byte[] lhs, byte[] rhs) {
660 if (isEquals == false) {
661 return this;
662 }
663 if (lhs == rhs) {
664 return this;
665 }
666 if (lhs == null || rhs == null) {
667 isEquals = false;
668 return this;
669 }
670 if (lhs.length != rhs.length) {
671 isEquals = false;
672 return this;
673 }
674 for (int i = 0; i < lhs.length && isEquals; ++i) {
675 append(lhs[i], rhs[i]);
676 }
677 return this;
678 }
679
680 /***
681 * <p>Deep comparison of array of <code>double</code>. Length and all
682 * values are compared.</p>
683 *
684 * <p>The method {@link #append(double, double)} is used.</p>
685 *
686 * @param lhs the left hand <code>double[]</code>
687 * @param rhs the right hand <code>double[]</code>
688 * @return EqualsBuilder - used to chain calls.
689 */
690 public EqualsBuilder append(double[] lhs, double[] rhs) {
691 if (isEquals == false) {
692 return this;
693 }
694 if (lhs == rhs) {
695 return this;
696 }
697 if (lhs == null || rhs == null) {
698 isEquals = false;
699 return this;
700 }
701 if (lhs.length != rhs.length) {
702 isEquals = false;
703 return this;
704 }
705 for (int i = 0; i < lhs.length && isEquals; ++i) {
706 append(lhs[i], rhs[i]);
707 }
708 return this;
709 }
710
711 /***
712 * <p>Deep comparison of array of <code>float</code>. Length and all
713 * values are compared.</p>
714 *
715 * <p>The method {@link #append(float, float)} is used.</p>
716 *
717 * @param lhs the left hand <code>float[]</code>
718 * @param rhs the right hand <code>float[]</code>
719 * @return EqualsBuilder - used to chain calls.
720 */
721 public EqualsBuilder append(float[] lhs, float[] rhs) {
722 if (isEquals == false) {
723 return this;
724 }
725 if (lhs == rhs) {
726 return this;
727 }
728 if (lhs == null || rhs == null) {
729 isEquals = false;
730 return this;
731 }
732 if (lhs.length != rhs.length) {
733 isEquals = false;
734 return this;
735 }
736 for (int i = 0; i < lhs.length && isEquals; ++i) {
737 append(lhs[i], rhs[i]);
738 }
739 return this;
740 }
741
742 /***
743 * <p>Deep comparison of array of <code>boolean</code>. Length and all
744 * values are compared.</p>
745 *
746 * <p>The method {@link #append(boolean, boolean)} is used.</p>
747 *
748 * @param lhs the left hand <code>boolean[]</code>
749 * @param rhs the right hand <code>boolean[]</code>
750 * @return EqualsBuilder - used to chain calls.
751 */
752 public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
753 if (isEquals == false) {
754 return this;
755 }
756 if (lhs == rhs) {
757 return this;
758 }
759 if (lhs == null || rhs == null) {
760 isEquals = false;
761 return this;
762 }
763 if (lhs.length != rhs.length) {
764 isEquals = false;
765 return this;
766 }
767 for (int i = 0; i < lhs.length && isEquals; ++i) {
768 append(lhs[i], rhs[i]);
769 }
770 return this;
771 }
772
773 /***
774 * <p>Return <code>true</code> if the fields that have been checked
775 * are all equal.</p>
776 *
777 * @return boolean
778 */
779 public boolean isEquals() {
780 return isEquals;
781 }
782
783 }