1 package se.citerus.dddsample.domain.shared.experimental;
2
3 import org.apache.commons.lang.builder.EqualsBuilder;
4 import org.apache.commons.lang.builder.HashCodeBuilder;
5 import se.citerus.dddsample.domain.shared.ValueObject;
6
7 /**
8 * Base class for value objects.
9 *
10 * @param <T>
11 */
12 public abstract class ValueObjectSupport<T extends ValueObject> implements ValueObject<T> {
13
14 private transient int cachedHashCode = 0;
15
16 /**
17 * @param other The other value object.
18 * @return True if all non-transient fields are equal.
19 */
20 @Override
21 public final boolean sameValueAs(final T other) {
22 return other != null && EqualsBuilder.reflectionEquals(this, other, false);
23 }
24
25 /**
26 * @return Hash code built from all non-transient fields.
27 */
28 @Override
29 public final int hashCode() {
30 // Using a local variable to ensure that we only do a single read
31 // of the cachedHashCode field, to avoid race conditions.
32 // It doesn't matter if several threads compute the hash code and overwrite
33 // each other, but it's important that we never return 0, which could happen
34 // with multiple reads of the cachedHashCode field.
35 //
36 // See java.lang.String.hashCode()
37 int h = cachedHashCode;
38 if (h == 0) {
39 // Lazy initialization of hash code.
40 // Value objects are immutable, so the hash code never changes.
41 h = HashCodeBuilder.reflectionHashCode(this, false);
42 cachedHashCode = h;
43 }
44
45 return h;
46 }
47
48 /**
49 * @param o other object
50 * @return True if other object has the same value as this value object.
51 */
52 @Override
53 public final boolean equals(final Object o) {
54 if (this == o) return true;
55 if (o == null || getClass() != o.getClass()) return false;
56
57 return sameValueAs((T) o);
58 }
59
60 }