In this article, we’ll explore the proper implementation of the equals() and hashCode() methods for JPA entities. While you can find a lot of implementations on the internet, it’s crucial to understand the reasoning behind the chosen implementations to avoid potential issues. By reading the entire article, you will: 
Gain insights about default equals() and hashCode() implementations;
Discover issues you might encounter using common equals() and hashCode() implementations found on the internet;
Learn a lot of interesting things about proxies in Hibernate.
However, if you’re short on time, you can skip to the end, copy the proper equals() and hashCode() methods, and paste them into your code :). 

Should We Override Equals and HashCode at All?

Let’s begin with a simple example. We have an online school application. Now, we need to create a REST endpoint that retrieves all students whose names start with specific letters and have an average grade lower than a certain value. Luckily, we already have a service with methods that can help us complete this task. 


@Table(name = “student”) 
public class Student { 
  @GeneratedValue(strategy = GenerationType.IDENTITY) 
  @Column(name = “id”, nullable = false) 
  private Long id; 
  @Column(name = “name”) 
  private String name; 
  @Column(name = “average_grade”) 
  private Short averageGrade; 


public interface StudentRepository extends JpaRepository<Student, Long> { 
  Set<Student> findByAverageGradeLessThan(Short averageGrade); 
  Set<Student> findByNameStartsWithIgnoreCase(String name); 



public class StudentService { 
  private final StudentRepository studentRepository; 
  public StudentService(StudentRepository studentRepository) { 
    this.studentRepository = studentRepository; 
  public Set<Student> getStudentsWithNameStartsWith(String letter) { 
    return studentRepository.findByNameStartsWithIgnoreCase(letter); 
  public Set<Student> getStudentsWithAverageGradeLessThan(Short averageGrade) { 
    return studentRepository.findByAverageGradeLessThan(averageGrade); 

So, the controller with the corresponding REST endpoint will look like this: 

Leave a Reply

Your email address will not be published. Required fields are marked *