View Javadoc

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  }