Mastering Efficient Auditable Entities in Your Spring Boot Symphony

Mainak Banerjee
Walmart Global Tech Blog
3 min readNov 20, 2023

Ah, data — the magical elixir that fuels our applications’ decision-making prowess, provides a backstage pass to performance insights, and reveals customer behaviour patterns, ultimately allowing us to finesse our apps like never before. Without it, we’d be fumbling in the dark, making guesses based on gut feelings, and trust me, our gut feelings about tech trends are far from accurate.

Now, in the bustling world of Spring Boot applications, data models or entities reign supreme. These entities act as the bridge between our app’s reality and its digital representation in a database. Think of them as the elegant emissaries between the digital and the real.

Data Dynamics — The Backbone of Informed Choices:

In the choreography of software, data is the lead dancer. It guides choices, exposes trends, and equips applications with intelligence. Without data, an application would be like a concert without a conductor — lost in cacophony. Data takes the center stage, enabling a dance of decision-making with data-backed moves.

Symphony of Entities — Mapping Data to Reality:

In the Spring Boot theatre, entities assume the roles of actors. Just as performers synchronise their steps, JPA entities reflect data structures. Imagine data metamorphosing into an entity, elegantly waltzing between memory and persistence. These entities encapsulate the soul of data.

Entities in JPA are nothing but POJOs representing data that can be persisted to the database. An entity represents a table stored in a database. Every instance of an entity represents a row in the table.

Unveiling Auditing — Building a Trail of Changes:

The saga deepens as auditing enters the scene. Auditable entities are the vigilant guardians, leaving footprints of every alteration in the system. They’re the backstage reporters capturing the drama of data’s evolution. Auditing provides a magnifying glass into the art of change, offering insights and possibilities for improvement.

Crafting the Canvas — The BaseAudit Blueprint:

The stage is set to design our auditable entities. Behold, the BaseAudit class, the masterpiece that streamlines the code. This class houses fields capturing the ‘who,’ ‘when,’ and ‘what’ of every entity performance. It’s a symphony of practicality, laying the foundation for a harmonious dance.

Auditing is an important part of any application, as it provides an audit trail of changes made to the system. Auditable entities allow developers to easily track and monitor changes that have been made to the system, as well as to identify areas where further improvement may be necessary.

Here’s an efficient way to structure our entities so that we can maintain an audit trail easily.

Mapper super class at the top of the inheritance pyramid

First off, we’ll start by creating a base class which will be making our code a lot leaner.

package auditable.entity;

import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import lombok.Data;

@MappedSuperclass
@Data
public class BaseAudit {
@Column(name = "created_by", nullable = false)
public String createdBy;

@Column(name = "last_modified_by", nullable = false)
public String lastModifiedBy;

@Column(name = "created_ts", nullable = false)
public ZonedDateTime createdTs;

@Column(name = "last_updated_ts", nullable = false)
public ZonedDateTime lastModifiedTs;

// This flag can be used to mark items as soft-deleted
@Column(name = "deleted", nullable = false)
public boolean deleted;

// This JPA hooks will set the created and last modified timestamps during creation
@PrePersist
protected void onCreate() {
createdTs = ZonedDateTime.now(ZoneOffset.UTC);
lastModifiedTs = ZonedDateTime.now(ZoneOffset.UTC);
}

// This JPA hook will update the last modified timestamps after entity is modified
@PreUpdate
protected void onUpdate() {
lastModifiedTs = ZonedDateTime.now(ZoneOffset.UTC);
}
}

A mapped superclass has no separate table defined for it.

Now let’s assume we have a Post entity which stores all the post data that has been posted by a user, which can be edited or deleted.

We can structure our Post entity like this :

package auditable.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;

@Data
@Entity
@Table(name = "post", schema = "auditable")
public class PostEntity extends BaseAudit {
@Id
@Column(name = "post_id", nullable = false)
private Long postId;

@Column(name = "text", nullable = false)
private String text;
}

Similarly we can create the Message Entity by extending the BaseAudit class.

--

--

Mainak Banerjee
Walmart Global Tech Blog

Mastery in code, goals on field I've showed. Dreamed Ma Long, now algorithms flowed. Music's my guide, in football I stride. A developer, passions worldwide.