Tagbangers Blog

Spring の小粋なクラス Part1 - AbstractPersistable

今回の小粋なクラスは、

org.springframework.data.jpa.domain.AbstractPersistable (spring-data-jpa-1.9.2.RELEASE)

JPA を使う時に Entity の親クラスとしてとりあえず継承しておくといい。

AbstractPersistable は JPA における主キーをあらわすメソッドと、主キーベースの #equals(Object) と #hashCode() メソッドが提供される。
下記のリファレンスにもあるとおり、Hibernate ではオブジェクトの等価性を使って同一のデータベースのレコードかどうかを判断する必要があるため、#equals(Object) と #hashCode() メソッドの実装が必須であり、実装忘れを防止できる。

https://docs.jboss.org/hibernate/stable/core/manual/en-US/html_single/#persistent-classes-equalshashcode

以下は AbstractPersistable のソースコード

/**
 * Abstract base class for entities. Allows parameterization of id type, chooses auto-generation and implements
 * {@link #equals(Object)} and {@link #hashCode()} based on that id.
 * 
 * @author Oliver Gierke
 * @author Thomas Darimont
 * @param <PK> the type of the identifier.
 */
@MappedSuperclass
public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> {

   private static final long serialVersionUID = -5554308939380869754L;

   @Id @GeneratedValue private PK id;

   /*
    * (non-Javadoc)
    * @see org.springframework.data.domain.Persistable#getId()
    */
   public PK getId() {
      return id;
   }

   /**
    * Sets the id of the entity.
    * 
    * @param id the id to set
    */
   protected void setId(final PK id) {
      this.id = id;
   }

   /**
    * Must be {@link Transient} in order to ensure that no JPA provider complains because of a missing setter.
    * 
    * @see DATAJPA-622
    * @see org.springframework.data.domain.Persistable#isNew()
    */
   @Transient
   public boolean isNew() {
      return null == getId();
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.lang.Object#toString()
    */
   @Override
   public String toString() {
      return String.format("Entity of type %s with id: %s", this.getClass().getName(), getId());
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.lang.Object#equals(java.lang.Object)
    */
   @Override
   public boolean equals(Object obj) {

      if (null == obj) {
         return false;
      }

      if (this == obj) {
         return true;
      }

      if (!getClass().equals(obj.getClass())) {
         return false;
      }

      AbstractPersistable<?> that = (AbstractPersistable<?>) obj;

      return null == this.getId() ? false : this.getId().equals(that.getId());
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.lang.Object#hashCode()
    */
   @Override
   public int hashCode() {

      int hashCode = 17;

      hashCode += null == getId() ? 0 : getId().hashCode() * 31;

      return hashCode;
   }
}