Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

equals/hashCode in Pojos and Records

28 views
Skip to first unread message

Simon Martinelli

unread,
Oct 22, 2024, 7:43:43 AM10/22/24
to jOOQ User Group
Hi,

I usually don't use Pojos but while preparing for a talk I used this feature.

pojosAsJavaRecordClasses
What's the reason for generating equals/hashCode and toString? Those are part of the Record spec anyway and are superfluous.

POJOs
equals/hashCode use all attributes. Why?
If the underlaying database table has a Primary or a Unique key only those attributes should be used.

Thanks, Simon

Lukas Eder

unread,
Oct 22, 2024, 9:26:47 AM10/22/24
to jooq...@googlegroups.com
On Tue, Oct 22, 2024 at 1:43 PM Simon Martinelli <simon.ma...@gmail.com> wrote:
Hi,

I usually don't use Pojos but while preparing for a talk I used this feature.

pojosAsJavaRecordClasses
What's the reason for generating equals/hashCode and toString? Those are part of the Record spec anyway and are superfluous.

Arrays aren't covered by Java's default implementations. Of course, you can still turn off the generation of these methods if you don't like them.
 
POJOs
equals/hashCode use all attributes. Why?
If the underlaying database table has a Primary or a Unique key only those attributes should be used.

Simon Martinelli

unread,
Oct 22, 2024, 10:31:46 AM10/22/24
to jooq...@googlegroups.com
Hi Lukas,

Thanks for the information.
Simon


--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jooq-user/CAB4ELO5dKcLvkr9JTbgQiD5qU%2BkhzvM%2B4U-eik8s6yf4C%2BZ5Wg%40mail.gmail.com.

Lukas Eder

unread,
Oct 22, 2024, 10:42:30 AM10/22/24
to jooq...@googlegroups.com
POJOs
equals/hashCode use all attributes. Why?
If the underlaying database table has a Primary or a Unique key only those attributes should be used.

See:

A similar request has come up on that issue where users wish to exclude certain columns from the equals() / hashCode() implementation (e.g. created_at, and other, similar audit columns). That could be implemented in addition to filters for primary keys:

I'll do both for jOOQ 3.20. 

Lukas Eder

unread,
Oct 22, 2024, 10:51:42 AM10/22/24
to jooq...@googlegroups.com
Simon,

What's your opinion on the equality of POJOs that don't have a value for a primary key yet (e.g. an identity)? There are at least these 3 strategies:

- All not-yet-stored objects are equal
- All not-yet-stored objects are non-equal (unless they have the same identity)
- Not-yet-stored objects are equal if their contents are equal (current behaviour)

My preference would be to treat them all as non-equal

Simon Martinelli

unread,
Oct 22, 2024, 11:03:54 AM10/22/24
to jooq...@googlegroups.com
That’s a tricky question.But I would say they are non-equal. 
You could have two objects with the same content, but you want to store them as two records.
For example, you have a log statement that happened at the same time and with the same content.

That’s what I usually implement when using JPA.


--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.

Lukas Eder

unread,
Oct 22, 2024, 11:06:47 AM10/22/24
to jooq...@googlegroups.com
I've summarised it here as well:

A log statement (assuming a log table) might not have a primary key at all, in case of which option 1 really does appear weird. Though, option 1 is consistent with https://github.com/jOOQ/jOOQ/issues/17487, where we simply include/exclude columns from the implementation.

Lukas Eder

unread,
Oct 23, 2024, 3:10:08 AM10/23/24
to jOOQ User Group
I've thought about this again. All 3 options (I'm not seeing others, at them moment) come with their own tradeoff. In terms of what jOOQ did historically, I think option 1 is the soundest. The rationale is that POJOs have always been value types in jOOQ, not entities. Their identity is irrelevant, only their contents count. Making the code generator ignore non-PK columns in equals() and hashCode() is simply a special case of making the code generator ignore *some* columns in equals() and hashCode(), as per this related feature request:

As such, option 1, where two NULL primary keys would mean the POJOs are equal would be consistent with the above #17487

It would also be consistent with the status quo. Today, if you create a table like this:

    CREATE TABLE t (i INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY);

You'd get a POJO with only 1 property, which is always NULL prior to creation. Today, equals() / hashCode() would completely depend on this single property's *value*, so today, two instances of new T() would be equal. It seems unwise and surprising to change this "magically" just because someone configured an alternative table like this to ignore the j column in equals() / hashCode():

    CREATE TABLE t (i INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, j INT);


Finally, it's important once more to stress what jOOQ thinks a POJO is. It's a bag of values, not an entity (as in JPA), even if historically, you can have the code generator annotate POJOs with JPA @Entity, @Table, @Column, etc. for better interoperability with JPA (a feature that I regret, like DAOs...).

Objections? Thoughts?

Alf Lervåg

unread,
Oct 23, 2024, 3:14:39 AM10/23/24
to jooq...@googlegroups.com
I’m partial to the value semantics of records as you describe with the option of ignoring specific fields. 

Alf Lervåg

23. okt. 2024 kl. 09:10 skrev Lukas Eder <lukas...@gmail.com>:

I've thought about this again. All 3 options (I'm not seeing others, at them moment) come with their own tradeoff. In terms of what jOOQ did historically, I think option 1 is the soundest. The rationale is that POJOs have always been value types in jOOQ, not entities. Their identity is irrelevant, only their contents count. Making the code generator ignore non-PK columns in equals() and hashCode() is simply a special case of making the code generator ignore *some* columns in equals() and hashCode(), as per this related feature request:

Simon Martinelli

unread,
Oct 23, 2024, 8:09:13 AM10/23/24
to jooq...@googlegroups.com
IMO, that’s the important message: “what jOOQ thinks a POJO is. It's a bag of values, not an entity”

As I said, I use DAOs and POJOs only for a demo because I have never found a real-life use case.

One of the issues with equals/hashCode is that if I use the POJOs together with some frameworks that use those methods, the current implementation is incorrect in the context of those frameworks.
For example, if I use a POJO in a Vaadin Grid and try to refresh the item in the Grid, this will not work because equals will return false after editing the POJO.
I had the same issue with the jOOQ Records and therefore created this https://github.com/72services/jooq-utilities

I share your opinion that DAOs, POJOs, and Java Records are not the core functionality and are not relevant for jOOQ.
And for compatibility reasons, it doesn’t make sense to change anything.


Lukas Eder

unread,
Oct 23, 2024, 8:29:58 AM10/23/24
to jooq...@googlegroups.com
Thanks for the clarification, Simon

On Wed, Oct 23, 2024 at 2:09 PM Simon Martinelli <simon.ma...@gmail.com> wrote:
IMO, that’s the important message: “what jOOQ thinks a POJO is. It's a bag of values, not an entity”

As I said, I use DAOs and POJOs only for a demo because I have never found a real-life use case.

If I had one wish, I'd wish you simply don't demo DAOs :)
 
One of the issues with equals/hashCode is that if I use the POJOs together with some frameworks that use those methods, the current implementation is incorrect in the context of those frameworks.
For example, if I use a POJO in a Vaadin Grid and try to refresh the item in the Grid, this will not work because equals will return false after editing the POJO.
I had the same issue with the jOOQ Records and therefore created this https://github.com/72services/jooq-utilities

Yes, this seems to be similar to putting any mutable objects in HashSets (e.g. ArrayList). Though perhaps, the Vaadin Grid should then use an IdentityHashMap to keep track of objects?

Simon Martinelli

unread,
Oct 23, 2024, 8:32:45 AM10/23/24
to jooq...@googlegroups.com
I’ve created the EqualsAndHashCode utility just for one customer because their UI is dynamic.

Normally if you don’t have control over equals and hashCode you can define a IdentityProvider for the grid and there for example, use the PK for it.
So the problem is solve,

--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.

Lukas Eder

unread,
Oct 24, 2024, 4:19:22 AM10/24/24
to jOOQ User Group
On Wednesday, October 23, 2024 at 2:09:13 PM UTC+2 simon.ma...@gmail.com wrote:
IMO, that’s the important message: “what jOOQ thinks a POJO is. It's a bag of values, not an entity”

I'll add this to the documentation to make it more clear:
Reply all
Reply to author
Forward
0 new messages