package org.appfuse.model; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.persistence.Transient; /** * BaseObject implementing equals and hashCode to be safe for * HashSets and HashMaps.<br> * Extended the class to contain some additional values, like * a version flag.<br><br> * This base implementation is not meant to be used by all sub- * classes. You are encouraged to implement your own equals and * hashCode methods, whenever you can find an appropriate businnes * key for your objects, which is immutable enough to last during * the lifetime of a hashed Collection. This implementation is * thought of as a makeshift for classes, where you cannot build * an immutable businness key. It also has one major drawback, see * comment of {@link #getObject()} for more information. * * * @see http://www.avaje.org/equals.html#gerry for details. * * @author Gerry Power<br> * Extended with JPA annotations by Tobias Vogel * */ @MappedSuperclass public abstract class BaseObjectIdentified extends BaseObject { private transient volatile Object object; private Long id; @Id @GeneratedValue(strategy=GenerationType.AUTO) public Long getId() { return this.id; } /** * Sets the id of this object * * @param id */ public void setId(Long id) { this.id = id; } /* (non-Javadoc) * @see org.appfuse.model.BaseObject#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { final boolean ret; if (obj instanceof BaseObjectIdentified) { return getObject().equals(((BaseObjectIdentified) obj).getObject()); } else { ret = false; } return ret; } /* (non-Javadoc) * @see org.appfuse.model.BaseObject#hashCode() */ @Override public int hashCode() { return getObject().hashCode(); } /** * Returns the identity object. If the object has not been persisted, * a new object is constructed, which will provide the hashCode of * this object during its lifetime. When an object is (re)loaded from * the database at a later time, the hashCode will always be generated * from the id.<br> * It does mean that a pre-persisted object and <b>new instance<b>/ * retrieved object will not be equal, but two new instances of the same * retrieved object will always be equal regardless of session or JVM. * So you can freely mix and match disconnected objects (even across JVMs), * and you can mix and match pre-persisted and persisted objects (with the * same JVM), but you can't mix and match newly retrieved and disconnected * objects with pre-persisted objects. * * @return The object to be used for hashCode and equals */ @Transient private Object getObject() { if ((object != null) || ((object == null) && (id == null))) { if (object == null) { synchronized (this) { if (object == null) { object = new Object(); } } } return object; } return id; } }