0

I'm sure the title can be improved so this question may become useful to a wider audience, but I'm not sure how.

I'm working on a small test project trying to provide JPA/Hibernate persistence to entities representing messages that are exchanged between a server and a client (the classes representing the messages are reused between both applications, but only the ones decoded/encoded by the server will be persisted).

The protocol supports three types of exchanges:

  • Sending a text to the server, which replies with an ACK message.
  • Sending some miscellaneous info to the server, which replies with the same ACK message format from above.
  • Sending a date/time request with a time zone to the server, which replies with the current date/time in that timezone.

All messages have the same header and footer format (in particular the header has a message type identifier and the footer has a checksum field), along with the mentioned payloads, which may be repeated among different messages from the same type, so they are not enough to uniquely identify a message of a given type from a persistence context.

Note that header and footer information is only relevant for the transmission context, so no persisting is required for them, only for the respective payloads and some persistence-related, uniquely identifying message id.

I've come up with a class design consisting of an abstract base class as well as one subclass for each message type (thus five distinct final subclasses), each of them with their payload fields. The base class has no fields besides a possible persistence-related id field in order to uniquely identify the message in the database.

I understand I need to provide proper equals() and hashCode() implementations for them, both for adding them to memory-based collections and for persisting them.

I've decided that the best O-R mapping for this hierarchy is a JOINED inheritance strategy which joins a base message table with individual message tables containing the respective payload fields. So the base message table will have an auto-generated primary key that is going to be mapped to the abstract message's id.

The question is two-fold actually. Basically I want to know how which should be the preferable equals() and hashCode() implementation approach for this scenario, but also in the case someone has concerns regarding the class design and chosen inheritance strategy, I'd ask if possible to let me know as well.

So in order to turn this into a useful question, I'm basically asking how should I override equals() and hashCode() in the case of entities with no original self-identifying ("business key") fields, all of them inheriting from the same abstract base class, which could contain a persistence-based identifier field.

I intend to design this to support newer protocols with newer message types, not necessarily from the same base class (unless I can make it a very general base class).

Piovezan
  • 3,215
  • 1
  • 28
  • 45
  • 1
    You don’t absolutely have to implement equals and hash code. For some cases you can do fine with the ones defined on Object. But if I have a collection that needs to hold persisted and not-yet-persisted entities, then I need the business key implementation. So I’m not clear what you’re doing that you would need your own implementations. – Nathan Hughes Feb 05 '21 at 00:04
  • It's for a TCP server that is supposed to interact with hardware and subject to supporting newer protocols and sending/receiving commands to/from the hardware, so I can expect incoming and outgoing messages to be added to collections as well as persisted. I can expect persisted message id's to be returned upon persisting and sent to other services. So from those requirements I figured I'd have to override `equals()` and `hashCode()`. So there's no need to in this case? What about the base message id field, I suppose I still need one, right? – Piovezan Feb 05 '21 at 00:21
  • Well then I conclude that if I have a class instance within the server application representing the connected hardware and its ever-changing properties, and I decide to persist it when they change, then it is going to need a business key field. Is that correct? I know this is a different question, it's just to be sure I got the idea. – Piovezan Feb 05 '21 at 00:40

1 Answers1

1

Unless you have to query all messages, I wouldn't use an inheritance mapping at all. In your case, since you share so few properties, it's probably best if you use the TABLE_PER_CLASS strategy.

Apart from that, I would recommend you always implement equals/hashCode based on the generated primary key sequence. This approach is only a problem if you put new entities i.e. without an id into hash based collections, persist them and then keep on using the hash based collection. If that is not the case, it's absolutely fine to just use the primary key for equals/hashCode.

Christian Beikov
  • 15,141
  • 2
  • 32
  • 58
  • Thanks. Yes, I don't see a point in querying all messages, so either `TABLE_PER_CLASS` or `@MappedSuperclass` seem the way to go. Messages are also intended to have a `created_on` timestamp. And providing a basic `equals`/`hashCode` override based on the `id` sounds a good idea. [This answer](https://stackoverflow.com/a/26826084/2241463) recommends `hashCode` to return a constant value in that case. – Piovezan Feb 10 '21 at 02:22
  • I wouldn't return a constant value if you can avoid the problematic case that I explained in my answer, but it's up to you. – Christian Beikov Feb 10 '21 at 08:32