Entities equals(), hashCode() and toString(). How to correctly implement them?
Solution 1
equals()
and hashCode()
should be implemented using a business key - i.e. a set of properties that uniquely identify the object, but are not its auto-generated ID.
in toString()
you can put whatever information is interesting - for example all fields.
Use your IDE (Eclipse, NetBeans, IntelliJ) to generate all these for you.
In order to avoid LazyInitializationException
, no matter whether in equals()
or in your view (jsp), you can use OpenSessionInView
.
Solution 2
When you implement the equals and hashCode methods for Hibernate objects, it is important to
- Use getters instead of directly accessing the class properties.
- Not directly compare objects' classes, but use
instanceof
instead
More information:
Stackoverflow: overriding-equals-and-hashcode-in-java
Hibernate documentation: Equals and HashCode
Edit: the same rules about not accessing the class properties directly applies to toString method as well - only using the getters guarantees that the information really contained in the class is returned.
Solution 3
- If two objects are equal, they must have the same hashcode.
- equals() method, by default, checks whether two references refer to the same in-memory instance on the Java heap
You can rely on Entity identifier to compare your Entity by using equals
public boolean equals(Object o) {
if(o == null)
return false;
Account account = (Account) o;
if(!(getId().equals(account.getId())))
return false;
return true;
}
But what happens when you have a non-persisted Entity. It will not work because its Identifier has not been assigned.
So Let's see what Java Persistence with Hibernate Book talks about it
A business key is a property, or some combination of properties, that is unique for each instance with the same database identity.
So
It is the natural key that you would use if you weren’t using a surrogate primary key instead.
So let's suppose you have a User Entity and its natural keys are firstName and lastName (At least, his/her firstName and lastName often does not change). So it would be implemented as
public boolean equals(Object o) {
if(o == null)
return false;
if(!(o instanceof User))
return false;
// Our natural key has not been filled
// So we must return false;
if(getFirstName() == null && getLastName() == null)
return false;
User user = (User) o;
if(!(getFirstName().equals(user.getFirstName())))
return false;
if(!(getLastName().equals(user.getLastName())))
return false;
return true;
}
// default implementation provided by NetBeans
public int hashcode() {
int hash = 3;
hash = 47 * hash + ((getFirstName() != null) ? getFirstName().hashcode() : 0)
hash = 47 * hash + ((getLastName() != null) ? getLastName().hashcode() : 0)
retrun hash;
}
It works fine! I use even with Mock objects like repositories, services etc
And about toString() method, as said by @Bozho, you can put whatever information is interesting. But remember some web frameworks, like Wicket and Vaadin, for instance, use this method to show its values.
spike07
Updated on November 20, 2020Comments
-
spike07 over 3 years
I'm implementing
equals()
,hashCode()
andtoString()
of my entities using all the available fields in the bean.I'm getting some Lazy init Exception on the frontend when I try to compare the equality or when I print the obj state. That's because some list in the entity can be lazy initialized.
I'm wondering what's the correct way to for implementing
equals()
andtoString()
on an entity object.