Overriding Hash Code and Equals in a Record with an Image Field

Overriding Hash Code and Equals in a Record with an Image Field


Java Records have several built-in implementations, so some ask when you should override that default behavior which is a situation I recently came across when dealing with GUI and binary image files, so I found an opportunity to write about this topic.

Example Case

This idea relates to when I was developing a JavaFX app that receives images via drag-and-drop, and had to override these methods to fix the bug in the GUI.

I already explained this, but I want to provide more documentation.

This snippet explains why, according to the use case I had with that app.

Why Override Hash Code and Equals Methods in a Record
Why Override Hash Code and Equals Methods in a Record

You may not use a binary file or large data like an Image to give an object equality, which leads us to overwrite the hashCode and equals methods in a Java record. Even though they’re implemented by default, we have to optimize sometimes.

The truth is that records are known to be “transparent carriers of immutable data,” but they can also contain mutable objects or images that reference disk effects. Whenever we see any scenario including “mutability, side effects, binary, etc.,” we have the red flag 🚩 to take action there.

If the behavior is not fixed, the side effects will cause problems in identifying the items. For example, when you update the image in the disk, the hashes will be different for the same item in the program, so two modified versions of the same item will match differently. Even if the image in the disk is the same, it’ll happen the same if you create two Image objects since they’ll match differently by just being different object instances. Moreover, using bloated fields to compute an object’s equality is nonsense programming logic and inefficient.

Updating an Existing Image

This behavior can be depicted as follows.

Let’s say I want to update the bird image by drag-and-drop.

Highlighting our Target
Highlighting our Target

If we don’t explicitly override the record hashCode, and equals methods according to our model, the Image binary field will introduce the side effect:

GUI Bug that Takes the Updated Image as Brand New
GUI Bug that Takes the Updated Image as Brand New

That is, when we add an existing image to the app, the list of images in the GUI doesn’t remove the old image since it takes both (old and new) images as different by being different instances of the same model.

Even though the file system keeps correctness (as that’s an application logic affair), that default record behavior still leads to correctness (and performance since you don’t want to compute an Image hash) issues on the front-end (as that’s a GUI affair).

This also shows us that we can have some side effects on less important parts of a system while keeping a robust design in the domain. I optimize as much as possible for the domain, and any professional software engineer also must.

Now, by fixing this detail, we get the correct behavior in the front-end as well:

Expected Update Behavior After Fixing the Bug
Expected Update Behavior After Fixing the Bug

Binary files are always a red flag 🚩 as they’re external systems that have to be pushed to the boundaries, like in FP: the DSL is part of the system, and side effects go to the boundaries.

This case shows one example of when to override the default implementation of a Java record that has large or binary fields and how a side effect can be mitigated in a system.

Update on the Application Development

As a bonus, I leave a pretty slide I created with the underlying application I was talking about in this article.

Regarding development, I finished the EP and will publish the complete development documentation as notified in Finishing Writing the Documentation for my Next EP (2023-07-14).

The article is published in Building Slides from Screenshots App in JavaFX.

Slides EP: Code Snippet
Slides EP: Code Snippet

I leave the old slide I used for this article at the beginning for the record (pun intended).

Legacy Third Party Slide
Legacy Third Party Slide

Notice the difference in quality this experimental version provides me compared to the generic code snippet images I generated above via other third-party tools that are always bugged or never work well. This opens a new era for my technical content creation.

Setting a Correct Object Equality

Large structures, binary files, memory addresses, and any kind of poorly-meaningful side effects have to be pushed to the system boundaries, and we have to avoid merging them into our domain boundaries like in this case where a record should be defined via a meaningful key from our application domain instead of an in-memory image object.