1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.oness.common.model.bo;
17
18 import java.lang.reflect.AccessibleObject;
19 import java.lang.reflect.Field;
20 import java.lang.reflect.Modifier;
21
22 import org.apache.commons.lang.builder.EqualsBuilder;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25
26 /***
27 * Customized EqualsBuilder ignoring fields that can't be accessed. Note that
28 * this behaviour can hide errors when testing.
29 *
30 * Only append(Object, Object) was modified.
31 *
32 * @see org.apache.commons.lang.builder.EqualsBuilder
33 *
34 * @author Carlos Sanchez
35 * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey </a>
36 * @author Stephen Colebourne
37 * @author Gary Gregory
38 * @author Pete Gieser
39 * @version $Revision: 1.2 $
40 */
41 public class ExceptionSafeEqualsBuilder extends EqualsBuilder {
42
43 private static Log log = LogFactory
44 .getLog(ExceptionSafeEqualsBuilder.class);
45
46 private boolean isEquals;
47
48 public ExceptionSafeEqualsBuilder() {
49 super();
50 isEquals = true;
51 }
52
53
54
55 public static boolean reflectionEquals(Object lhs, Object rhs) {
56 return reflectionEquals(lhs, rhs, false, null);
57 }
58
59 public static boolean reflectionEquals(Object lhs, Object rhs,
60 boolean testTransients) {
61 return reflectionEquals(lhs, rhs, testTransients, null);
62 }
63
64 public static boolean reflectionEquals(Object lhs, Object rhs,
65 boolean testTransients, Class reflectUpToClass) {
66 if (lhs == rhs) {
67 return true;
68 }
69 if (lhs == null || rhs == null) {
70 return false;
71 }
72
73
74
75
76 Class lhsClass = lhs.getClass();
77 Class rhsClass = rhs.getClass();
78 Class testClass;
79 if (lhsClass.isInstance(rhs)) {
80 testClass = lhsClass;
81 if (!rhsClass.isInstance(lhs)) {
82
83 testClass = rhsClass;
84 }
85 } else if (rhsClass.isInstance(lhs)) {
86 testClass = rhsClass;
87 if (!lhsClass.isInstance(rhs)) {
88
89 testClass = lhsClass;
90 }
91 } else {
92
93 return false;
94 }
95 ExceptionSafeEqualsBuilder equalsBuilder = new ExceptionSafeEqualsBuilder();
96 try {
97 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
98 while (testClass.getSuperclass() != null
99 && testClass != reflectUpToClass) {
100 testClass = testClass.getSuperclass();
101 reflectionAppend(lhs, rhs, testClass, equalsBuilder,
102 testTransients);
103 }
104 } catch (IllegalArgumentException e) {
105
106
107
108
109
110
111 return false;
112 }
113 return equalsBuilder.isEquals();
114 }
115
116 private static void reflectionAppend(Object lhs, Object rhs, Class clazz,
117 ExceptionSafeEqualsBuilder builder, boolean useTransients) {
118 Field[] fields = clazz.getDeclaredFields();
119 AccessibleObject.setAccessible(fields, true);
120 for (int i = 0; i < fields.length && builder.isEquals; i++) {
121 Field f = fields[i];
122 if ((f.getName().indexOf('$') == -1)
123 && (useTransients || !Modifier
124 .isTransient(f.getModifiers()))
125 && (!Modifier.isStatic(f.getModifiers()))) {
126 try {
127 builder.append(f.get(lhs), f.get(rhs));
128 } catch (IllegalAccessException e) {
129
130
131 throw new InternalError("Unexpected IllegalAccessException");
132 }
133 }
134 }
135 }
136
137
138
139 public EqualsBuilder appendSuper(boolean superEquals) {
140 if (isEquals == false) {
141 return this;
142 }
143 isEquals = superEquals;
144 return this;
145 }
146
147
148
149 public EqualsBuilder append(Object lhs, Object rhs) {
150 if (isEquals == false) {
151 return this;
152 }
153 if (lhs == rhs) {
154 return this;
155 }
156 if (lhs == null || rhs == null) {
157 if (log.isInfoEnabled()) {
158 log.info("Equals failed: " + lhs + " is not equal to " + rhs);
159 }
160 isEquals = false;
161 return this;
162 }
163 Class lhsClass = lhs.getClass();
164 if (!lhsClass.isArray()) {
165
166
167
168 try {
169
170
171 boolean b = lhs.equals(rhs);
172 if (!b && log.isInfoEnabled()) {
173 log.info("Equals failed: [" + lhs.getClass().getName()
174 + "] " + lhs + " is not equal to ["
175 + rhs.getClass().getName() + "] " + rhs);
176 }
177 isEquals = b;
178
179 } catch (Exception e) {
180
181 if (log.isInfoEnabled()) {
182 log.info("Ignored field in equals method due to exception: "
183 + e.getLocalizedMessage());
184 }
185 }
186
187
188
189 } else {
190
191
192 if (lhs instanceof long[]) {
193 append((long[]) lhs, (long[]) rhs);
194 } else if (lhs instanceof int[]) {
195 append((int[]) lhs, (int[]) rhs);
196 } else if (lhs instanceof short[]) {
197 append((short[]) lhs, (short[]) rhs);
198 } else if (lhs instanceof char[]) {
199 append((char[]) lhs, (char[]) rhs);
200 } else if (lhs instanceof byte[]) {
201 append((byte[]) lhs, (byte[]) rhs);
202 } else if (lhs instanceof double[]) {
203 append((double[]) lhs, (double[]) rhs);
204 } else if (lhs instanceof float[]) {
205 append((float[]) lhs, (float[]) rhs);
206 } else if (lhs instanceof boolean[]) {
207 append((boolean[]) lhs, (boolean[]) rhs);
208 } else {
209
210 append((Object[]) lhs, (Object[]) rhs);
211 }
212 }
213 return this;
214 }
215
216 public EqualsBuilder append(long lhs, long rhs) {
217 if (isEquals == false) {
218 return this;
219 }
220 isEquals = (lhs == rhs);
221 return this;
222 }
223
224 public EqualsBuilder append(int lhs, int rhs) {
225 if (isEquals == false) {
226 return this;
227 }
228 isEquals = (lhs == rhs);
229 return this;
230 }
231
232 public EqualsBuilder append(short lhs, short rhs) {
233 if (isEquals == false) {
234 return this;
235 }
236 isEquals = (lhs == rhs);
237 return this;
238 }
239
240 public EqualsBuilder append(char lhs, char rhs) {
241 if (isEquals == false) {
242 return this;
243 }
244 isEquals = (lhs == rhs);
245 return this;
246 }
247
248 public EqualsBuilder append(byte lhs, byte rhs) {
249 if (isEquals == false) {
250 return this;
251 }
252 isEquals = (lhs == rhs);
253 return this;
254 }
255
256 public EqualsBuilder append(double lhs, double rhs) {
257 if (isEquals == false) {
258 return this;
259 }
260 return append(Double.doubleToLongBits(lhs), Double
261 .doubleToLongBits(rhs));
262 }
263
264 public EqualsBuilder append(float lhs, float rhs) {
265 if (isEquals == false) {
266 return this;
267 }
268 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
269 }
270
271 public EqualsBuilder append(boolean lhs, boolean rhs) {
272 if (isEquals == false) {
273 return this;
274 }
275 isEquals = (lhs == rhs);
276 return this;
277 }
278
279 public EqualsBuilder append(Object[] lhs, Object[] rhs) {
280 if (isEquals == false) {
281 return this;
282 }
283 if (lhs == rhs) {
284 return this;
285 }
286 if (lhs == null || rhs == null) {
287 isEquals = false;
288 return this;
289 }
290 if (lhs.length != rhs.length) {
291 isEquals = false;
292 return this;
293 }
294 for (int i = 0; i < lhs.length && isEquals; ++i) {
295 Class lhsClass = lhs[i].getClass();
296 if (!lhsClass.isInstance(rhs[i])) {
297 isEquals = false;
298 break;
299 }
300 append(lhs[i], rhs[i]);
301 }
302 return this;
303 }
304
305 public EqualsBuilder append(long[] lhs, long[] rhs) {
306 if (isEquals == false) {
307 return this;
308 }
309 if (lhs == rhs) {
310 return this;
311 }
312 if (lhs == null || rhs == null) {
313 isEquals = false;
314 return this;
315 }
316 if (lhs.length != rhs.length) {
317 isEquals = false;
318 return this;
319 }
320 for (int i = 0; i < lhs.length && isEquals; ++i) {
321 append(lhs[i], rhs[i]);
322 }
323 return this;
324 }
325
326 public EqualsBuilder append(int[] lhs, int[] rhs) {
327 if (isEquals == false) {
328 return this;
329 }
330 if (lhs == rhs) {
331 return this;
332 }
333 if (lhs == null || rhs == null) {
334 isEquals = false;
335 return this;
336 }
337 if (lhs.length != rhs.length) {
338 isEquals = false;
339 return this;
340 }
341 for (int i = 0; i < lhs.length && isEquals; ++i) {
342 append(lhs[i], rhs[i]);
343 }
344 return this;
345 }
346
347 public EqualsBuilder append(short[] lhs, short[] rhs) {
348 if (isEquals == false) {
349 return this;
350 }
351 if (lhs == rhs) {
352 return this;
353 }
354 if (lhs == null || rhs == null) {
355 isEquals = false;
356 return this;
357 }
358 if (lhs.length != rhs.length) {
359 isEquals = false;
360 return this;
361 }
362 for (int i = 0; i < lhs.length && isEquals; ++i) {
363 append(lhs[i], rhs[i]);
364 }
365 return this;
366 }
367
368 public EqualsBuilder append(char[] lhs, char[] rhs) {
369 if (isEquals == false) {
370 return this;
371 }
372 if (lhs == rhs) {
373 return this;
374 }
375 if (lhs == null || rhs == null) {
376 isEquals = false;
377 return this;
378 }
379 if (lhs.length != rhs.length) {
380 isEquals = false;
381 return this;
382 }
383 for (int i = 0; i < lhs.length && isEquals; ++i) {
384 append(lhs[i], rhs[i]);
385 }
386 return this;
387 }
388
389 public EqualsBuilder append(byte[] lhs, byte[] rhs) {
390 if (isEquals == false) {
391 return this;
392 }
393 if (lhs == rhs) {
394 return this;
395 }
396 if (lhs == null || rhs == null) {
397 isEquals = false;
398 return this;
399 }
400 if (lhs.length != rhs.length) {
401 isEquals = false;
402 return this;
403 }
404 for (int i = 0; i < lhs.length && isEquals; ++i) {
405 append(lhs[i], rhs[i]);
406 }
407 return this;
408 }
409
410 public EqualsBuilder append(double[] lhs, double[] rhs) {
411 if (isEquals == false) {
412 return this;
413 }
414 if (lhs == rhs) {
415 return this;
416 }
417 if (lhs == null || rhs == null) {
418 isEquals = false;
419 return this;
420 }
421 if (lhs.length != rhs.length) {
422 isEquals = false;
423 return this;
424 }
425 for (int i = 0; i < lhs.length && isEquals; ++i) {
426 append(lhs[i], rhs[i]);
427 }
428 return this;
429 }
430
431 public EqualsBuilder append(float[] lhs, float[] rhs) {
432 if (isEquals == false) {
433 return this;
434 }
435 if (lhs == rhs) {
436 return this;
437 }
438 if (lhs == null || rhs == null) {
439 isEquals = false;
440 return this;
441 }
442 if (lhs.length != rhs.length) {
443 isEquals = false;
444 return this;
445 }
446 for (int i = 0; i < lhs.length && isEquals; ++i) {
447 append(lhs[i], rhs[i]);
448 }
449 return this;
450 }
451
452 public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
453 if (isEquals == false) {
454 return this;
455 }
456 if (lhs == rhs) {
457 return this;
458 }
459 if (lhs == null || rhs == null) {
460 isEquals = false;
461 return this;
462 }
463 if (lhs.length != rhs.length) {
464 isEquals = false;
465 return this;
466 }
467 for (int i = 0; i < lhs.length && isEquals; ++i) {
468 append(lhs[i], rhs[i]);
469 }
470 return this;
471 }
472
473 public boolean isEquals() {
474 return isEquals;
475 }
476
477 }