I have a domain object called User. Properties of user include ssoId, name, email, createdBy, createdDate and userRole. Of these, ssoId must be unique in the sense no two users can have the same sso id. So my equals method checks for the sso id and returns either true or false.
@Override public boolean equals(Object o) {
if (!(o instanceof User))
return false;
return user.getSsoId().equals((User)o.getSsoId());
}
What I feel is that this is an incorrect implementation, though it is correct as far as the business rules are concerned. The above implementation will return true for two objects with same sso id but with different values for say name or email or both. Should I change my equals contract to check the equality of all fields? What is your suggestion?
This is (almost) correct for "technical equality", but not for "natural equality". To achieve top technical equality, you should also test the reflexive o == this
. It may happen that the object isn't persisted in DB yet and thus doesn't have a technical ID yet. E.g.
public class User {
private Long id;
@Override
public boolean equals(Object object) {
return (object instanceof User) && (id != null)
? id.equals(((User) object).id)
: (object == this);
}
@Override
public int hashCode() {
return (id != null)
? (User.class.hashCode() + id.hashCode())
: super.hashCode();
}
}
For "natural equality" you should rather compare all non-technical properties. For "real world entities" this is after all more robust (but also more expensive) than technical equality.
public class User {
private String name;
private Date birth;
private int housenumber;
private long phonenumber;
@Override
public boolean equals(Object object) {
// Basic checks.
if (object == this) return true;
if (!(object instanceof User)) return false;
// Property checks.
User other = (User) object;
return Objects.equals(name, other.name)
&& Objects.equals(birth, other.birth)
&& (housenumber == other.housenumber)
&& (phonenumber == other.phonenumber);
}
@Override
public int hashCode() {
return Objects.hash(name, birth, housenumber, phonenumber);
}
}
True, that's lot of code when there are a lot of properties. A bit decent IDE (Eclipse, Netbeans, etc) can just autogenerate equals()
, hashCode()
(and also toString()
, getters and setters) for you. Take benefit of it. In Eclipse, rightclick code and peek the Source (Alt+Shift+S) menu option.
If in your model ssoid must be unique, that implies that the values for the other fields should not be different for two instances of User. If you want to validate that assumption, you could do so with assertions within the equals method if the overhead is not an issue.
What you're doing seems fine, and you're not violating any of the rules that equals
must follow.
You may still want to check other fields, not to change equals
's semantics, but to detect an inconsistency in your business logic, and possibly trigger an assertion/exception.
This is a tricky decision to make.
This is a spot i got into when considering hashing a few months ago. I would suggest you read up on what a hash is because it is highly relevant to your answer ... i suggest that you are looking to implement some kind of hash and test its equality.
There are different kinds of equality ... there is the equality of the identity of the object, the equality of the data of the object, the equality of the entire object ... you could also include audit information in there also.
The fact is that 'equal' has many possible meanings.
I resolved this by implementing equal as a strict equality across all fields simply because after asking around it seems to be the intuitive meaning of equals. I then constructed methos for the other kinds of equality i required and defined an interface to wrap these.
I wouldnt test equality on object == this because often you are testing two different objects with the same data which in my book are equal despite them referring to different memory addresses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With