Equals and HashCode and Hibernate
In one of my current consulting projects the topic of implementing equals and hashCode in Hibernate domain model classes was discussed again so I decided to write down how I deal with that in my projects.
First I encourage every Java developer to read chapter 3 of Effective Java from Joshua Bloch - which is available online here (the whole book is great but chapter 3 deals with methods common to all objects). Basically chapter 3 says you have to obey the contracts when overriding equals (item 7) and to always override hashCode when overriding equals (item 8). These contracts are also documented in the Java API doc.
When using Hibernate for persistence you have to decide if and how to implement hashCode and equals with that background and with the knowledge of your domain model. There is a wiki document discussing this topic which you should read. The most important headline here is “Separating object id and business key”.
In my applications this means that for example the important parts of a User class looks like:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String login;
}
In this case the id property is the object id used by Hibernate to identify the object and the login property is the business key. The hashCode and equals method of this User class look like:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getLogin() == null) ? 0 : getLogin().hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (Hibernate.getClass(this) != Hibernate.getClass(obj)) {
return false;
}
final User other = (User) obj;
if (getLogin() == null) {
if (other.getLogin() != null) {
return false;
}
} else if (!getLogin().equals(other.getLogin())) {
return false;
}
return true;
}
It is important to notice that only the business key (the login property) is used for calculating the hashCode and to check if two objects are equal otherwise you will get strange behavior in HashSet and HashMaps containing objects of this type.