Implementing Object.equals(Object) by natural keys

The last section's result actually provides a hint to implement Object.equals(Object) in a more meaningful way. The problem comparing transient instances occurs since a surrogate key's value is being provided by the database server only at the time an entity is being persisted. If at least one natural key (sometimes referred to as business key) is being defined this one may be used instead:

Figure 946. Implementing Object.equals(Object) by natural keys
package session3;

	    @Table(uniqueConstraints={@UniqueConstraint(columnNames={"uid"}) ,
	    public class User {
	    String uid;

	    public String getUid() {return uid;}
	    public void setUid(String uid) {this.uid = uid;}
	    public boolean equals(Object other) {
	    if (this == other) {
	    return true;
	    } else if (other instanceof User) {
	    return getUid().equals(((User) other).getUid()); 
	    } else {
	    return false;
	    public int hashCode() {
	    if (null == getUid()) {
	    return System.identityHashCode(this);
	    } else {
	    return getUid().hashCode(); 

Definition of property session3.User.getUid() to become a natural key.

Two session3.User instances having identical session3.User.getUid() values will be considered equal.

The session3.User.hashCode() implementation has to be changed accordingly.

exercise No. 24

Method and field access


Consider Figure 946, “Implementing Object.equals(Object) by natural keys ”. You may get a different runtime behaviour when using this.uid().equals( that.uid() ) at . Execute the corresponding session3.CompareNewlyCreated and session3.LoadUser applications and explain the result.


JPA allows lazy fetch mode typically enabled by default. So the uid attribute's initialization will be deferred until session3.User.getUid() is being called for the first time.