Subclass: object is not equal to an instance of a trivial subclass with equal fields
Subclass: object is not equal to an instance of a trivial subclass with equal fields: ...
Consider making the class final.
This error occurs when a class is non-final, and an instance of this class is not equal to an instance of a (dynamically generated) subclass of this class, even though their fields are all equal. It is easy to break the equals contract when inheritance is involved, even accidentally, and EqualsVerifier will always err on the side of caution.
There are several ways to fix this problem:
Make the class final
Make the class final. This way, all inheritance headaches will be avoided. However, this is not always possible.
Use instanceof
In frameworks like Java EE and Hibernate, it’s often not allowed to make certain classes final, even if you don’t intend to subclass them. In these cases, it’s probably a safe bet that the framework will create dynamic proxy subclasses for you class. This error will most likely only pop up if you use getClass()
in your equals method, like so:
The solution, then, is to use an instanceof
test instead:
This way, a dynamic proxy subclass generated by the framework can still be equal to an object that you instantiate directly.
Unfortunately, with Hibernate it’s not possible to make the equals
and hashCode
methods final as well. This means it’s still possible to accidentally (or purposely) break the contract by making a subclass and overriding equals
and hashCode
.
Make equals
and hashCode
final
If you do intend your class to be overridden, but subclasses won’t add state that needs to be included in the equals
/hashCode
contract, the above advice applies as well. Again, make you equals
and hashCode
methods final, to signal that no such state is to be added in subclasses.
Use canEqual
If you intend your class to be overridden, and you also want subclasses to add state that needs to be included in the contract, things get complicated. In Item 8 of Effective Java, Josh Bloch argues that it is impossible to achieve this without breaking the contract. Nevertheless, it turns out to be possible, by introducing a new method called canEqual
. This article by Martin Odersky, Bill Venners and Lex Spoon explains how to achieve this. If you decide to go down this path, you will need to supply EqualsVerifier with an example of a subclass with added state, like this:
Obligatory RTFM comment
You can read more about handling inheritance in the manual.