Entities equals(), hashCode() and toString(). How to correctly implement them?

31,933

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

  1. Use getters instead of directly accessing the class properties.
  2. 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

  1. If two objects are equal, they must have the same hashcode.
  2. 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.

Share:
31,933
spike07
Author by

spike07

Updated on November 20, 2020

Comments

  • spike07
    spike07 over 3 years

    I'm implementing equals(), hashCode() and toString() 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() and toString() on an entity object.