I have this @Override for equals() in my MyClass class:
public class MyClass extends MySuperClass
{
...
@Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || this.getClass() != o.getClass() )
{
return false;
}
if ( !super.equals( o ) )
{
return false;
}
MyClass that = ( MyClass ) o;
return this.var1.equals( that.var1 ) && this.var2.equals( that.var2 );
}
...
}
Pretty standard. Matter of fact, it follows Java best practices.
Later in life I have this in another sub-package class (my controller class):
...
package com.a.b.api.controllers;
...
import com.a.b.jpa.models.MyClass;
...
MyClass myObject1 = new MyClass( var1, var2 );
MyClass myObject2 = this.myClassRepository.getById( 1 ); // SpringBoot/Jpa/Hibernate
if ( myObject2.equals( myObject1 ) )
{
...do something...
}
...
this.myClassRepository.save( myObject1 );
...
My problem is that the .equals() is always failing here:
if ( o == null || this.getClass() != o.getClass() )
because java says that this.getClass() and o.getClass() are NOT equal. When I debug the code (in Intellij IDEA 2022.1 UE) I see this:
this.getClass() = MyClass@13706
but
o.getClass = com.a.b.jpa.models.MyClass@8f7462
But they are the same class! Almost every Java book, tutorial, blog, Intellij IDEA, etc. demonstrates the .equals() this way. I have tried this in Ubuntu 20.04.4 LTS java-14-openjdk-amd64 and java-17-openjdk-amd64 with the same results.
What am I doing wrong?
CodePudding user response:
myObject2
is an instance of a proxy class, generated at runtime by Hibernate using Byte Buddy. The generated proxy intercepts all method invocations, that's why getClass()
returns different results.
As an alternative to getClass()
, using instanceof
might be another approach:
if ( !(this instanceof MyClass && o instanceof MyClass) )
{
return false;
}
However keep in mind that instanceof
has its drawbacks. It violates the symmetry principle.
You shouldn't compare these objects in the first place, since a new object should be different from a Hibernate managed one that has a persistent state.
CodePudding user response:
You are not using a best practice. Change your equals to be something like the following (null check first, then same check, then class check):
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != getClass()) {
return false;
}
... do the actual comparison here
}
Note: the code above is a paraphrase of Apache EqualsBuilder
CodePudding user response:
I use this standard equals
and hashcode
implementations for JPA entities (as described here):
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof MyClass)) {
return false;
}
MyClass other = (MyClass) o;
return id != null && id.equals(other.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}