Customize Lombok equalsAndHashCode() on list attribute

86 views Asked by At

Is there a way to customize the Lombok equalsAndHashCode() on list attribute?

I have a subclass that looks like so:

public class subClass extends superClass {
    private List<Long> ids;

For 2 subClass objs, I consider them as equal if they have 1 or more ids in common.

I can write my own logic for it but is there a way to customize this equal logic in Lombok?

1

There are 1 answers

0
rzwitserloot On BEST ANSWER

I can write my own logic for it but is there a way to customize this equal logic in Lombok?

There is. But you cannot do what you want. Not because of lombok, but because equals and hashCode do not allow you to do this.

problem 1: hashcode

There's a rule. If 2 objects are equal, their hashcode MUST BE equal. (the reverse need not be true; 2 objects with equal hashcodes do not have to be equal).

So how in the blazes would you write a hashCode impl that adheres to this rule? The only feasible option is return 0; - all instances of subClass have the same hashCode. Which obliterates any point of trying to use such a class in many contexts where you want equals at all, such as in hashmap. It's highly dubious to do this, but what other option do you have?

problem 2: Equivalence rules

Whenever you override a method (i.e. implement a method defined by a supertype), you have to adhere to the contract. This at the very minimum involves the signature line: Your override must have the same name, parameter types, and return type (or strictly compatible expansions of this), or you've failed to adhere to the contract, and the compiler will refuse to compile if you mess that up.

But that is not the only contract you have to adhere to.

Not everything can be checked by the compiler. However, just because the compiler doesn't check it doesn't mean the rule doesn't exist or that you can just ignore it.

You cannot do this without breaking the contract.

The specific problem is the rule of equivalence. The equals contract states that implementation must adhere to a bunch of rules. The rule that is problematic here is this one:

If a.equals(b) and b.equals(c), then a.equals(c) must be true

And you can't do that.

Imagine A having ids [1,2,3], B having ids [2,3,4] and C having ids [4,5,6].

A is equals to B in your setup (because they have 2 and 3 in common), and B is equal to C as well (because they have 4 in common). But A and C are not equal to each other as they have no ID in common and that breaks the contract.