JPA Auditing — Spring Boot & Spring Security

Amila Iroshan
The Fresh Writes
Published in
5 min readJan 26, 2024

The purpose of this article is to discuss about how we can configure JPA (Java Persistence API) auditing with Spring Boot application to automatically handle the auditing for any entity. We will create a simple Spring Boot CRUD REST APIs and we implement auditing using spring data JPA.

1). Introduction to JPA Auditing

Auditing is a fundamental aspect of software development, especially when dealing with data-driven applications. It involves tracking changes to data, monitoring user actions, and maintaining a historical record of these activities. In the context of Spring Boot applications, auditing plays a crucial role in ensuring data integrity, security, and compliance with regulatory requirements.

2). Why JPA Auditing?

The process of tracking and logging events on the Database is called Database Auditing. Auditing helps us to find out when the changes were made and who has made them.

Database Audit is very important for compliance purposes and also to analyze production issues.

· Data Integrity: It helps maintain data consistency and prevents unauthorized or malicious changes.

· Security: Auditing aids in identifying and responding to security breaches or suspicious activities.

· Compliance: Many industries and applications require auditing to comply with regulations and standards.

· Troubleshooting: It simplifies the process of identifying and resolving issues by providing a historical trail of actions.

3). How to achieve JPA Auditing with Spring Data JPA

Spring Data JPA, an integral part of the Spring Data project, simplifies database access with JPA and enhances auditing capabilities. In this section, we will explore the built-in auditing annotations provided by Spring Data JPA, including @CreatedBy, @CreatedDate, @LastModifiedBy, and @LastModifiedDate. These annotations empower you to effortlessly incorporate auditing attributes into your entity classes, automating the auditing process with ease.

@CreatedBy — This field is used to record the name of the user who has created the record. It can be a human or a system.
@CreatedDate — This field is used to store the date on which the record was created.
@LastModifiedBy — This field is used to record the name of the user that has updated the record. It can be a human or a system.
@LastModifiedDate — This field is used to store the date on which the record was updated.

4). Implement JPA Auditing in Spring Boot

4.1 Initializing the Project

Use the Spring Initializer with the following settings to create the initial application.

· Project: Maven

· Language: Java

· Packaging: Jar

· Java: 17

· Spring Boot: 3.1.x (e.g., 3.1.2)

· Dependencies

+ Spring Data JPA

+ Spring Web

+ MySQL JDBC Driver

+ Lombok

+ Spring Devtools

+ Spring Security

Leave the rest of the settings as it is. Click “Generate” to download the project zip file. Extract it and open it with your IDE.

4.2 Project Structure

Figure 1. Project Structure

4.3 Defining Data Source

Figure 2. Data base Configuration

4.4 Define Base Auditing Entity

Figure 3. Base Auditing Entity

If you are auditing multiple entities, then it is common practice to extract common fields with a base class and extend it. Therefore, instead of creating createdBy, createdDate, lastModifiedBy, and lastModifiedDate properties in each entity, we can move the createdBy, createdDate, lastModifiedBy, lastModifiedDate properties to a base class, Auditable, and annotate this base class with @MappedSuperClass.

@MappedSuperclass annotation to mark this class as a non-persistent class and hibernate will not create/look up a table mapping for this class.

@EntityListeners(AuditingEntityListener.class) If you annotate an entity class with @EntityListeners, you can specify one or more listener classes that implement the corresponding JPA callback methods. These methods will be invoked automatically when specified events occur on the entity, such as entity creation, update, or deletion.

AuditingEntityListener is a built-in entity listener class provided by Spring Data JPA for auditing purposes. It is used in conjunction with auditing annotations (@CreatedBy, @LastModifiedBy, @CreatedDate, @LastModifiedDate) to automatically populate auditing-related fields in entities.

4.5 Define JPA Entity Which Extends the Auditing Entity

Figure 4. JPA Entity Class

4.6 Auditing Author Using AuditorAware and Spring Security

To tell JPA about currently logged-in users, we will need to provide an implementation of AuditorAware and override the getCurrentAuditor() method. And inside getCurrentAuditor(), we will need to fetch a currently logged-in user.

For the demonstration purposes, we have created two users who are admin and supplier for create and update functionalities respectively.

In addition to that, We can provide a hard-coded user, as a currently logged-in user by using AuditorAware.

Figure 5. AuditorAware with Spring Security
Figure 6. Hard Coded AuditorAware

4.7 Enable JPA Auditing by Using @EnableJpaAuditing

Figure 7. Enable JPA Auditing

4.8 Configure Spring Security

Figure 8. Enable Spring Security

5). Unit Test for JPA Audit

@Autowired
private SupplierRepository supplierRepository;
@Mock
private SecurityContext securityContext;
@Mock
private Authentication authentication;
@BeforeEach
public void init(){
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
when(authentication.isAuthenticated()).thenReturn(true);
}
@Test
public void testCreatedByAuditing(){
//mock authenticated username
when(authentication.getName()).thenReturn("admin");
//create a supplier
Supplier supplier = Supplier.builder().name("Saman").contactDetails("0778956345").address("No:02,Kaluthara RD,Colombo 10").specialties("Dress").build();
Supplier actualResult=supplierRepository.save(supplier);
//verify that createdBy and createdDate
assertEquals(actualResult.getCreatedBy(),"admin");
assertNotNull(actualResult.getCreatedDate());
}

@Test
public void testModifiedByAuditing(){
//mock authenticated username
when(authentication.getName()).thenReturn("admin");
//create a supplier
Supplier supplier = Supplier.builder().name("Amal").contactDetails("0778345534").address("No:02,Galle RD,Colombo 10").specialties("Meat").build();
supplierRepository.save(supplier);
when(authentication.getName()).thenReturn("supplier");
//update the authenticate username
Supplier updatedSupplier= Supplier.builder().id(supplier.getId()).name("Amal_test").contactDetails("0778345534").address("No:03,Galle RD,Colombo 10").specialties("Meat").build();
Supplier actualResult=supplierRepository.save(updatedSupplier);
//verify that createdBy and createdDate
assertEquals(actualResult.getLastModifiedBy(),"supplier");
assertNotNull(actualResult.getLastModifiedDate());
}

6). Run the project and test output.

Use Maven on terminal or your IDEs run configuration to start the application.

6.1 Testing Application using postman REST client.

6.1.1 Test Result 01 — Create new supplier with user ‘admin’

Figure 9. Test Result 01

6.1.2 Test Result 02 — Modify Existing Supplier with user ‘supplier’

Figure 10. Test Result 02

Conclusion

In this comprehensive guide, we’ve explored the implementing auditing in Spring Boot applications using JPA, Hibernate, and Spring Data JPA. Spring Data JPA’s auditing annotations proved to be a powerful tool in automating auditing processes.

You can find the complete code for this example on my GitHub

Thank you for read this article and If you like this article, do follow and clap 👏🏻.Happy coding, Cheers !!😊😊

--

--

Amila Iroshan
The Fresh Writes

Software Engineer | Open Source Contributor | Tech Enthusiast