1 package se.citerus.dddsample.domain.shared.experimental;
2
3 import java.lang.reflect.Field;
4
5
6
7
8
9 public abstract class EntitySupport<T extends Entity, ID> implements Entity<T, ID> {
10
11 private static Field identityField;
12
13 @Override
14 public final boolean sameIdentityAs(final T other) {
15 return other != null && this.identity().equals(other.identity());
16 }
17
18 @Override
19 public final ID identity() {
20 if (identityField == null) {
21 identityField = identityFieldLazyDetermination(this.getClass());
22 }
23
24 try {
25 return (ID) identityField.get(this);
26 } catch (IllegalAccessException e) {
27 throw new RuntimeException(e);
28 }
29 }
30
31 private static Field identityFieldLazyDetermination(final Class cls) {
32 Field identityField = null;
33
34 for (Field field : cls.getDeclaredFields()) {
35 if (field.getAnnotation(Identity.class) != null) {
36 field.setAccessible(true);
37 if (identityField != null) {
38 throw new IllegalStateException("Only one field can be annotated with " + Identity.class);
39 } else {
40 identityField = field;
41 }
42 }
43 }
44
45 if (identityField == null) {
46 if (cls == Object.class) {
47 throw new IllegalStateException(
48 "This class, or one of its superclasses, " +
49 "must have a unique field annotated with " + Identity.class);
50 } else {
51 return identityFieldLazyDetermination(cls.getSuperclass());
52 }
53 }
54
55 return identityField;
56 }
57
58 @Override
59 public final int hashCode() {
60 return identity().hashCode();
61 }
62
63 @Override
64 public final boolean equals(final Object o) {
65 if (this == o) return true;
66 if (o == null || getClass() != o.getClass()) return false;
67
68 return sameIdentityAs((T) o);
69 }
70
71 }